plotly.js 1.52.1 → 1.52.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.fossa.yml +58 -0
  2. package/.ignore +3 -0
  3. package/CHANGELOG.md +21 -0
  4. package/dist/README.md +25 -25
  5. package/dist/plot-schema.json +8 -8
  6. package/dist/plotly-basic.js +187 -54
  7. package/dist/plotly-basic.min.js +2 -2
  8. package/dist/plotly-cartesian.js +187 -54
  9. package/dist/plotly-cartesian.min.js +2 -2
  10. package/dist/plotly-finance.js +187 -54
  11. package/dist/plotly-finance.min.js +2 -2
  12. package/dist/plotly-geo-assets.js +2 -2
  13. package/dist/plotly-geo.js +168 -49
  14. package/dist/plotly-geo.min.js +2 -2
  15. package/dist/plotly-gl2d.js +173 -51
  16. package/dist/plotly-gl2d.min.js +2 -2
  17. package/dist/plotly-gl3d.js +668 -449
  18. package/dist/plotly-gl3d.min.js +2 -2
  19. package/dist/plotly-mapbox.js +170 -50
  20. package/dist/plotly-mapbox.min.js +2 -2
  21. package/dist/plotly-with-meta.js +823 -533
  22. package/dist/plotly.js +814 -525
  23. package/dist/plotly.min.js +2 -2
  24. package/package.json +24 -23
  25. package/src/assets/geo_assets.js +1 -1
  26. package/src/components/annotations/attributes.js +1 -1
  27. package/src/core.js +1 -1
  28. package/src/lib/index.js +6 -3
  29. package/src/plot_api/subroutines.js +6 -0
  30. package/src/plot_api/validate.js +4 -3
  31. package/src/plots/cartesian/axes.js +6 -2
  32. package/src/plots/cartesian/constants.js +1 -2
  33. package/src/plots/cartesian/layout_defaults.js +112 -27
  34. package/src/plots/gl3d/scene.js +361 -323
  35. package/src/plots/layout_attributes.js +2 -2
  36. package/src/plots/mapbox/layers.js +2 -1
  37. package/src/plots/plots.js +30 -9
  38. package/src/traces/bar/hover.js +6 -1
  39. package/src/traces/bar/plot.js +13 -4
  40. package/src/traces/mesh3d/convert.js +9 -5
  41. package/src/traces/pie/attributes.js +7 -6
  42. package/src/traces/treemap/plot.js +2 -0
  43. package/tasks/test_syntax.js +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * plotly.js (gl3d) v1.52.1
2
+ * plotly.js (gl3d) v1.52.2
3
3
  * Copyright 2012-2020, Plotly, Inc.
4
4
  * All rights reserved.
5
5
  * Licensed under the MIT license
@@ -29358,6 +29358,7 @@ function SimplicialMesh(gl
29358
29358
  this.contourColor = [0,0,0]
29359
29359
  this.contourEnable = true
29360
29360
 
29361
+ this.pickVertex = true;
29361
29362
  this.pickId = 1
29362
29363
  this.bounds = [
29363
29364
  [ Infinity, Infinity, Infinity],
@@ -29439,21 +29440,6 @@ function genColormap(param, opacityscale) {
29439
29440
  return ndarray(result, [256,256,4], [4,0,1])
29440
29441
  }
29441
29442
 
29442
- function unpackIntensity(cells, numVerts, cellIntensity) {
29443
- var result = new Array(numVerts)
29444
- for(var i=0; i<numVerts; ++i) {
29445
- result[i] = 0
29446
- }
29447
- var numCells = cells.length
29448
- for(var i=0; i<numCells; ++i) {
29449
- var c = cells[i]
29450
- for(var j=0; j<c.length; ++j) {
29451
- result[c[j]] = cellIntensity[i]
29452
- }
29453
- }
29454
- return result
29455
- }
29456
-
29457
29443
  function takeZComponent(array) {
29458
29444
  var n = array.length
29459
29445
  var result = new Array(n)
@@ -29644,11 +29630,13 @@ proto.update = function(params) {
29644
29630
  if(vertexIntensity) {
29645
29631
  this.intensity = vertexIntensity
29646
29632
  } else if(cellIntensity) {
29647
- this.intensity = unpackIntensity(cells, positions.length, cellIntensity)
29633
+ this.intensity = cellIntensity
29648
29634
  } else {
29649
29635
  this.intensity = takeZComponent(positions)
29650
29636
  }
29651
29637
 
29638
+ this.pickVertex = !(cellIntensity || cellColors)
29639
+
29652
29640
  //Point size
29653
29641
  var pointSizes = params.pointSizes
29654
29642
  var meshPointSize = params.pointSize || 1.0
@@ -30090,9 +30078,34 @@ proto.pick = function(pickData) {
30090
30078
  simplex[i] = positions[cell[i]]
30091
30079
  }
30092
30080
 
30081
+ var x = pickData.coord[0];
30082
+ var y = pickData.coord[1];
30083
+
30084
+ if(!this.pickVertex) {
30085
+ var A = this.positions[cell[0]];
30086
+ var B = this.positions[cell[1]];
30087
+ var C = this.positions[cell[2]];
30088
+
30089
+ var dataCoordinate = [
30090
+ (A[0] + B[0] + C[0]) / 3,
30091
+ (A[1] + B[1] + C[1]) / 3,
30092
+ (A[2] + B[2] + C[2]) / 3
30093
+ ]
30094
+
30095
+ return {
30096
+ _cellCenter : true,
30097
+ position: [x, y],
30098
+ index: cellId,
30099
+ cell: cell,
30100
+ cellId: cellId,
30101
+ intensity: this.intensity[cellId],
30102
+ dataCoordinate: dataCoordinate
30103
+ }
30104
+ }
30105
+
30093
30106
  var data = closestPoint(
30094
30107
  simplex,
30095
- [pickData.coord[0], this._resolution[1]-pickData.coord[1]],
30108
+ [x * this.pixelRatio, this._resolution[1] - y * this.pixelRatio],
30096
30109
  this._model,
30097
30110
  this._view,
30098
30111
  this._projection,
@@ -30727,6 +30740,10 @@ function createScene(options) {
30727
30740
 
30728
30741
  var gl = options.gl
30729
30742
  if(!gl) {
30743
+ if(options.glOptions) {
30744
+ isMobile = !!options.glOptions.preserveDrawingBuffer
30745
+ }
30746
+
30730
30747
  gl = getContext(canvas,
30731
30748
  options.glOptions || {
30732
30749
  premultipliedAlpha: true,
@@ -30746,7 +30763,7 @@ function createScene(options) {
30746
30763
 
30747
30764
  //Accumulation buffer
30748
30765
  var accumBuffer = createFBO(gl,
30749
- [gl.drawingBufferWidth, gl.drawingBufferHeight], {
30766
+ gl.drawingBufferWidth, gl.drawingBufferHeight, {
30750
30767
  preferFloat: !isMobile
30751
30768
  })
30752
30769
 
@@ -30794,7 +30811,7 @@ function createScene(options) {
30794
30811
  view: null,
30795
30812
  projection: projection,
30796
30813
  model: model,
30797
- _ortho: false
30814
+ _ortho: false
30798
30815
  }
30799
30816
 
30800
30817
  var pickDirty = true
@@ -30849,6 +30866,29 @@ function createScene(options) {
30849
30866
  this.aspect[0] = aspectratio.x
30850
30867
  this.aspect[1] = aspectratio.y
30851
30868
  this.aspect[2] = aspectratio.z
30869
+ },
30870
+
30871
+ setBounds: function(axisIndex, range) {
30872
+ this.bounds[0][axisIndex] = range.min
30873
+ this.bounds[1][axisIndex] = range.max
30874
+ },
30875
+
30876
+ setClearColor: function(clearColor) {
30877
+ this.clearColor = clearColor
30878
+ },
30879
+
30880
+ clearRGBA: function() {
30881
+ this.gl.clearColor(
30882
+ this.clearColor[0],
30883
+ this.clearColor[1],
30884
+ this.clearColor[2],
30885
+ this.clearColor[3]
30886
+ )
30887
+
30888
+ this.gl.clear(
30889
+ this.gl.COLOR_BUFFER_BIT |
30890
+ this.gl.DEPTH_BUFFER_BIT
30891
+ )
30852
30892
  }
30853
30893
  }
30854
30894
 
@@ -31247,48 +31287,7 @@ function createScene(options) {
31247
31287
  pickShape[1] = Math.max(height/scene.pixelRatio, 1)|0
31248
31288
 
31249
31289
  //Compute camera parameters
31250
-
31251
- if(isOrtho) {
31252
- ortho(projection,
31253
- -width/height,
31254
- width/height,
31255
- -1,
31256
- 1,
31257
- scene.zNear,
31258
- scene.zFar
31259
- )
31260
- cameraParams._ortho = true
31261
- } else {
31262
- perspective(projection,
31263
- scene.fovy,
31264
- width/height,
31265
- scene.zNear,
31266
- scene.zFar
31267
- )
31268
- cameraParams._ortho = false
31269
- }
31270
-
31271
- //Compute model matrix
31272
- for(var i=0; i<16; ++i) {
31273
- model[i] = 0
31274
- }
31275
- model[15] = 1
31276
-
31277
- var maxS = 0
31278
- for(var i=0; i<3; ++i) {
31279
- maxS = Math.max(maxS, bounds[1][i] - bounds[0][i])
31280
- }
31281
-
31282
- for(var i=0; i<3; ++i) {
31283
- if(scene.autoScale) {
31284
- model[5*i] = scene.aspect[i] / (bounds[1][i] - bounds[0][i])
31285
- } else {
31286
- model[5*i] = 1 / maxS
31287
- }
31288
- if(scene.autoCenter) {
31289
- model[12+i] = -model[5*i] * 0.5 * (bounds[0][i] + bounds[1][i])
31290
- }
31291
- }
31290
+ calcCameraParams(scene, isOrtho)
31292
31291
 
31293
31292
  //Apply axes/clip bounds
31294
31293
  for(var i=0; i<numObjs; ++i) {
@@ -31336,9 +31335,8 @@ function createScene(options) {
31336
31335
  // 3. composite final scene
31337
31336
 
31338
31337
  //Clear FBO
31339
- var clearColor = scene.clearColor
31340
- gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3])
31341
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
31338
+ scene.clearRGBA()
31339
+
31342
31340
  gl.depthMask(true)
31343
31341
  gl.colorMask(true, true, true, true)
31344
31342
  gl.enable(gl.DEPTH_TEST)
@@ -31458,6 +31456,63 @@ function createScene(options) {
31458
31456
  return scene
31459
31457
  }
31460
31458
 
31459
+ function calcCameraParams(scene, isOrtho) {
31460
+ var bounds = scene.bounds
31461
+ var cameraParams = scene.cameraParams
31462
+ var projection = cameraParams.projection
31463
+ var model = cameraParams.model
31464
+
31465
+ var width = scene.gl.drawingBufferWidth
31466
+ var height = scene.gl.drawingBufferHeight
31467
+ var zNear = scene.zNear
31468
+ var zFar = scene.zFar
31469
+ var fovy = scene.fovy
31470
+
31471
+ var r = width / height
31472
+
31473
+ if(isOrtho) {
31474
+ ortho(projection,
31475
+ -r,
31476
+ r,
31477
+ -1,
31478
+ 1,
31479
+ zNear,
31480
+ zFar
31481
+ )
31482
+ cameraParams._ortho = true
31483
+ } else {
31484
+ perspective(projection,
31485
+ fovy,
31486
+ r,
31487
+ zNear,
31488
+ zFar
31489
+ )
31490
+ cameraParams._ortho = false
31491
+ }
31492
+
31493
+ //Compute model matrix
31494
+ for(var i=0; i<16; ++i) {
31495
+ model[i] = 0
31496
+ }
31497
+ model[15] = 1
31498
+
31499
+ var maxS = 0
31500
+ for(var i=0; i<3; ++i) {
31501
+ maxS = Math.max(maxS, bounds[1][i] - bounds[0][i])
31502
+ }
31503
+
31504
+ for(var i=0; i<3; ++i) {
31505
+ if(scene.autoScale) {
31506
+ model[5*i] = scene.aspect[i] / (bounds[1][i] - bounds[0][i])
31507
+ } else {
31508
+ model[5*i] = 1 / maxS
31509
+ }
31510
+ if(scene.autoCenter) {
31511
+ model[12+i] = -model[5*i] * 0.5 * (bounds[0][i] + bounds[1][i])
31512
+ }
31513
+ }
31514
+ }
31515
+
31461
31516
  },{"./camera.js":141,"./lib/shader":142,"a-big-triangle":12,"gl-axes3d":96,"gl-axes3d/properties":103,"gl-fbo":112,"gl-mat4/ortho":128,"gl-mat4/perspective":129,"gl-select-static":149,"gl-spikes3d":158,"is-mobile":260,"mouse-change":271}],144:[function(_dereq_,module,exports){
31462
31517
  module.exports = slerp
31463
31518
 
@@ -32686,8 +32741,11 @@ proto.dispose = function() {
32686
32741
  }
32687
32742
 
32688
32743
  function createSelectBuffer(gl, shape) {
32689
- var fbo = createFBO(gl, shape)
32690
- var buffer = pool.mallocUint8(shape[0]*shape[1]*4)
32744
+ var width = shape[0]
32745
+ var height = shape[1]
32746
+ var options = {}
32747
+ var fbo = createFBO(gl, width, height, options)
32748
+ var buffer = pool.mallocUint8(width*height*4)
32691
32749
  return new SelectBuffer(gl, fbo, buffer)
32692
32750
  }
32693
32751
 
@@ -73176,7 +73234,7 @@ exports.svgAttrs = {
73176
73234
  'use strict';
73177
73235
 
73178
73236
  // package version injected by `npm run preprocess`
73179
- exports.version = '1.52.1';
73237
+ exports.version = '1.52.2';
73180
73238
 
73181
73239
  // inject promise polyfill
73182
73240
  _dereq_('es6-promise').polyfill();
@@ -76867,11 +76925,14 @@ lib.templateString = function(string, obj) {
76867
76925
  var getterCache = {};
76868
76926
 
76869
76927
  return string.replace(lib.TEMPLATE_STRING_REGEX, function(dummy, key) {
76928
+ var v;
76870
76929
  if(SIMPLE_PROPERTY_REGEX.test(key)) {
76871
- return obj[key] || '';
76930
+ v = obj[key];
76931
+ } else {
76932
+ getterCache[key] = getterCache[key] || lib.nestedProperty(obj, key).get;
76933
+ v = getterCache[key]();
76872
76934
  }
76873
- getterCache[key] = getterCache[key] || lib.nestedProperty(obj, key).get;
76874
- return getterCache[key]() || '';
76935
+ return lib.isValidTextValue(v) ? v : '';
76875
76936
  });
76876
76937
  };
76877
76938
 
@@ -87142,6 +87203,7 @@ exports.doAutoRangeAndConstraints = function(gd) {
87142
87203
  var fullLayout = gd._fullLayout;
87143
87204
  var axList = Axes.list(gd, '', true);
87144
87205
  var matchGroups = fullLayout._axisMatchGroups || [];
87206
+ var axLookup = {};
87145
87207
  var ax;
87146
87208
  var axRng;
87147
87209
 
@@ -87149,6 +87211,7 @@ exports.doAutoRangeAndConstraints = function(gd) {
87149
87211
  ax = axList[i];
87150
87212
  cleanAxisConstraints(gd, ax);
87151
87213
  doAutoRange(gd, ax);
87214
+ axLookup[ax._id] = 1;
87152
87215
  }
87153
87216
 
87154
87217
  enforceAxisConstraints(gd);
@@ -87161,6 +87224,10 @@ exports.doAutoRangeAndConstraints = function(gd) {
87161
87224
 
87162
87225
  for(id in group) {
87163
87226
  ax = Axes.getFromId(gd, id);
87227
+
87228
+ // skip over 'missing' axes which do not pass through doAutoRange
87229
+ if(!axLookup[ax._id]) continue;
87230
+ // if one axis has autorange false, we're done
87164
87231
  if(ax.autorange === false) continue groupLoop;
87165
87232
 
87166
87233
  axRng = Lib.simpleMap(ax.range, ax.r2l);
@@ -88038,13 +88105,14 @@ function crawl(objIn, objOut, schema, list, base, path) {
88038
88105
  var valOut = objOut[k];
88039
88106
 
88040
88107
  var nestedSchema = getNestedSchema(schema, k);
88041
- var isInfoArray = (nestedSchema || {}).valType === 'info_array';
88042
- var isColorscale = (nestedSchema || {}).valType === 'colorscale';
88108
+ var nestedValType = (nestedSchema || {}).valType;
88109
+ var isInfoArray = nestedValType === 'info_array';
88110
+ var isColorscale = nestedValType === 'colorscale';
88043
88111
  var items = (nestedSchema || {}).items;
88044
88112
 
88045
88113
  if(!isInSchema(schema, k)) {
88046
88114
  list.push(format('schema', base, p));
88047
- } else if(isPlainObject(valIn) && isPlainObject(valOut)) {
88115
+ } else if(isPlainObject(valIn) && isPlainObject(valOut) && nestedValType !== 'any') {
88048
88116
  crawl(valIn, valOut, nestedSchema, list, base, p);
88049
88117
  } else if(isInfoArray && isArray(valIn)) {
88050
88118
  if(valIn.length > valOut.length) {
@@ -90849,10 +90917,14 @@ axes.drawOne = function(gd, ax, opts) {
90849
90917
  var axId = ax._id;
90850
90918
  var axLetter = axId.charAt(0);
90851
90919
  var counterLetter = axes.counterLetter(axId);
90852
- var mainLinePosition = ax._mainLinePosition;
90853
- var mainMirrorPosition = ax._mainMirrorPosition;
90854
90920
  var mainPlotinfo = fullLayout._plots[ax._mainSubplot];
90921
+
90922
+ // this happens when updating matched group with 'missing' axes
90923
+ if(!mainPlotinfo) return;
90924
+
90855
90925
  var mainAxLayer = mainPlotinfo[axLetter + 'axislayer'];
90926
+ var mainLinePosition = ax._mainLinePosition;
90927
+ var mainMirrorPosition = ax._mainMirrorPosition;
90856
90928
 
90857
90929
  var vals = ax._vals = axes.calcTicks(ax);
90858
90930
 
@@ -92811,11 +92883,10 @@ exports.tick0 = function(tick0, axType, calendar, dtick) {
92811
92883
  */
92812
92884
 
92813
92885
  'use strict';
92814
- var counterRegex = _dereq_('../../lib/regex').counter;
92815
92886
 
92887
+ var counterRegex = _dereq_('../../lib/regex').counter;
92816
92888
 
92817
92889
  module.exports = {
92818
-
92819
92890
  idRegex: {
92820
92891
  x: counterRegex('x'),
92821
92892
  y: counterRegex('y')
@@ -96005,6 +96076,8 @@ var axisIds = _dereq_('./axis_ids');
96005
96076
  var id2name = axisIds.id2name;
96006
96077
  var name2id = axisIds.name2id;
96007
96078
 
96079
+ var AX_ID_PATTERN = _dereq_('./constants').AX_ID_PATTERN;
96080
+
96008
96081
  var Registry = _dereq_('../../registry');
96009
96082
  var traceIs = Registry.traceIs;
96010
96083
  var getComponentMethod = Registry.getComponentMethod;
@@ -96114,7 +96187,28 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
96114
96187
 
96115
96188
  var bgColor = Color.combine(plotBgColor, layoutOut.paper_bgcolor);
96116
96189
 
96117
- var axName, axLetter, axLayoutIn, axLayoutOut;
96190
+ // name of single axis (e.g. 'xaxis', 'yaxis2')
96191
+ var axName;
96192
+ // id of single axis (e.g. 'y', 'x5')
96193
+ var axId;
96194
+ // 'x' or 'y'
96195
+ var axLetter;
96196
+ // input layout axis container
96197
+ var axLayoutIn;
96198
+ // full layout axis container
96199
+ var axLayoutOut;
96200
+
96201
+ function newAxLayoutOut() {
96202
+ var traces = ax2traces[axName] || [];
96203
+ axLayoutOut._traceIndices = traces.map(function(t) { return t._expandedIndex; });
96204
+ axLayoutOut._annIndices = [];
96205
+ axLayoutOut._shapeIndices = [];
96206
+ axLayoutOut._imgIndices = [];
96207
+ axLayoutOut._subplotsWith = [];
96208
+ axLayoutOut._counterAxes = [];
96209
+ axLayoutOut._name = axLayoutOut._attr = axName;
96210
+ axLayoutOut._id = axId;
96211
+ }
96118
96212
 
96119
96213
  function coerce(attr, dflt) {
96120
96214
  return Lib.coerce(axLayoutIn, axLayoutOut, layoutAttributes, attr, dflt);
@@ -96128,9 +96222,6 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
96128
96222
  return (axLetter === 'x') ? yIds : xIds;
96129
96223
  }
96130
96224
 
96131
- var counterAxes = {x: getCounterAxes('x'), y: getCounterAxes('y')};
96132
- var allAxisIds = counterAxes.x.concat(counterAxes.y);
96133
-
96134
96225
  function getOverlayableAxes(axLetter, axName) {
96135
96226
  var list = (axLetter === 'x') ? xNames : yNames;
96136
96227
  var out = [];
@@ -96146,9 +96237,30 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
96146
96237
  return out;
96147
96238
  }
96148
96239
 
96240
+ // list of available counter axis names
96241
+ var counterAxes = {x: getCounterAxes('x'), y: getCounterAxes('y')};
96242
+ // list of all x AND y axis ids
96243
+ var allAxisIds = counterAxes.x.concat(counterAxes.y);
96244
+ // lookup and list of axis ids that axes in axNames have a reference to,
96245
+ // even though they are missing from allAxisIds
96246
+ var missingMatchedAxisIdsLookup = {};
96247
+ var missingMatchedAxisIds = [];
96248
+
96249
+ // fill in 'missing' axis lookup when an axis is set to match an axis
96250
+ // not part of the allAxisIds list, save axis type so that we can propagate
96251
+ // it to the missing axes
96252
+ function addMissingMatchedAxis() {
96253
+ var matchesIn = axLayoutIn.matches;
96254
+ if(AX_ID_PATTERN.test(matchesIn) && allAxisIds.indexOf(matchesIn) === -1) {
96255
+ missingMatchedAxisIdsLookup[matchesIn] = axLayoutIn.type;
96256
+ missingMatchedAxisIds = Object.keys(missingMatchedAxisIdsLookup);
96257
+ }
96258
+ }
96259
+
96149
96260
  // first pass creates the containers, determines types, and handles most of the settings
96150
96261
  for(i = 0; i < axNames.length; i++) {
96151
96262
  axName = axNames[i];
96263
+ axId = name2id(axName);
96152
96264
  axLetter = axName.charAt(0);
96153
96265
 
96154
96266
  if(!Lib.isPlainObject(layoutIn[axName])) {
@@ -96157,20 +96269,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
96157
96269
 
96158
96270
  axLayoutIn = layoutIn[axName];
96159
96271
  axLayoutOut = Template.newContainer(layoutOut, axName, axLetter + 'axis');
96160
-
96161
- var traces = ax2traces[axName] || [];
96162
- axLayoutOut._traceIndices = traces.map(function(t) { return t._expandedIndex; });
96163
- axLayoutOut._annIndices = [];
96164
- axLayoutOut._shapeIndices = [];
96165
- axLayoutOut._imgIndices = [];
96166
- axLayoutOut._subplotsWith = [];
96167
- axLayoutOut._counterAxes = [];
96168
-
96169
- // set up some private properties
96170
- axLayoutOut._name = axLayoutOut._attr = axName;
96171
- var id = axLayoutOut._id = name2id(axName);
96172
-
96173
- var overlayableAxes = getOverlayableAxes(axLetter, axName);
96272
+ newAxLayoutOut();
96174
96273
 
96175
96274
  var visibleDflt =
96176
96275
  (axLetter === 'x' && !xaMustDisplay[axName] && xaMayHide[axName]) ||
@@ -96188,13 +96287,13 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
96188
96287
  font: layoutOut.font,
96189
96288
  outerTicks: outerTicks[axName],
96190
96289
  showGrid: !noGrids[axName],
96191
- data: traces,
96290
+ data: ax2traces[axName] || [],
96192
96291
  bgColor: bgColor,
96193
96292
  calendar: layoutOut.calendar,
96194
96293
  automargin: true,
96195
96294
  visibleDflt: visibleDflt,
96196
96295
  reverseDflt: reverseDflt,
96197
- splomStash: ((layoutOut._splomAxes || {})[axLetter] || {})[id]
96296
+ splomStash: ((layoutOut._splomAxes || {})[axLetter] || {})[axId]
96198
96297
  };
96199
96298
 
96200
96299
  coerce('uirevision', layoutOut.uirevision);
@@ -96220,12 +96319,63 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
96220
96319
  handlePositionDefaults(axLayoutIn, axLayoutOut, coerce, {
96221
96320
  letter: axLetter,
96222
96321
  counterAxes: counterAxes[axLetter],
96223
- overlayableAxes: overlayableAxes,
96322
+ overlayableAxes: getOverlayableAxes(axLetter, axName),
96224
96323
  grid: layoutOut.grid
96225
96324
  });
96226
96325
 
96227
96326
  coerce('title.standoff');
96228
96327
 
96328
+ addMissingMatchedAxis();
96329
+
96330
+ axLayoutOut._input = axLayoutIn;
96331
+ }
96332
+
96333
+ // coerce the 'missing' axes
96334
+ i = 0;
96335
+ while(i < missingMatchedAxisIds.length) {
96336
+ axId = missingMatchedAxisIds[i++];
96337
+ axName = id2name(axId);
96338
+ axLetter = axName.charAt(0);
96339
+
96340
+ if(!Lib.isPlainObject(layoutIn[axName])) {
96341
+ layoutIn[axName] = {};
96342
+ }
96343
+
96344
+ axLayoutIn = layoutIn[axName];
96345
+ axLayoutOut = Template.newContainer(layoutOut, axName, axLetter + 'axis');
96346
+ newAxLayoutOut();
96347
+
96348
+ var defaultOptions2 = {
96349
+ letter: axLetter,
96350
+ font: layoutOut.font,
96351
+ outerTicks: outerTicks[axName],
96352
+ showGrid: !noGrids[axName],
96353
+ data: [],
96354
+ bgColor: bgColor,
96355
+ calendar: layoutOut.calendar,
96356
+ automargin: true,
96357
+ visibleDflt: false,
96358
+ reverseDflt: false,
96359
+ splomStash: ((layoutOut._splomAxes || {})[axLetter] || {})[axId]
96360
+ };
96361
+
96362
+ coerce('uirevision', layoutOut.uirevision);
96363
+
96364
+ axLayoutOut.type = missingMatchedAxisIdsLookup[axId] || 'linear';
96365
+
96366
+ handleAxisDefaults(axLayoutIn, axLayoutOut, coerce, defaultOptions2, layoutOut);
96367
+
96368
+ handlePositionDefaults(axLayoutIn, axLayoutOut, coerce, {
96369
+ letter: axLetter,
96370
+ counterAxes: counterAxes[axLetter],
96371
+ overlayableAxes: getOverlayableAxes(axLetter, axName),
96372
+ grid: layoutOut.grid
96373
+ });
96374
+
96375
+ coerce('fixedrange');
96376
+
96377
+ addMissingMatchedAxis();
96378
+
96229
96379
  axLayoutOut._input = axLayoutIn;
96230
96380
  }
96231
96381
 
@@ -96276,9 +96426,12 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
96276
96426
  var constraintGroups = layoutOut._axisConstraintGroups = [];
96277
96427
  // similar to _axisConstraintGroups, but for matching axes
96278
96428
  var matchGroups = layoutOut._axisMatchGroups = [];
96429
+ // make sure to include 'missing' axes here
96430
+ var allAxisIdsIncludingMissing = allAxisIds.concat(missingMatchedAxisIds);
96431
+ var axNamesIncludingMissing = axNames.concat(Lib.simpleMap(missingMatchedAxisIds, id2name));
96279
96432
 
96280
- for(i = 0; i < axNames.length; i++) {
96281
- axName = axNames[i];
96433
+ for(i = 0; i < axNamesIncludingMissing.length; i++) {
96434
+ axName = axNamesIncludingMissing[i];
96282
96435
  axLetter = axName.charAt(0);
96283
96436
  axLayoutIn = layoutIn[axName];
96284
96437
  axLayoutOut = layoutOut[axName];
@@ -96286,15 +96439,19 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
96286
96439
  var scaleanchorDflt;
96287
96440
  if(axLetter === 'y' && !axLayoutIn.hasOwnProperty('scaleanchor') && axHasImage[axName]) {
96288
96441
  scaleanchorDflt = axLayoutOut.anchor;
96289
- } else {scaleanchorDflt = undefined;}
96442
+ } else {
96443
+ scaleanchorDflt = undefined;
96444
+ }
96290
96445
 
96291
96446
  var constrainDflt;
96292
96447
  if(!axLayoutIn.hasOwnProperty('constrain') && axHasImage[axName]) {
96293
96448
  constrainDflt = 'domain';
96294
- } else {constrainDflt = undefined;}
96449
+ } else {
96450
+ constrainDflt = undefined;
96451
+ }
96295
96452
 
96296
96453
  handleConstraintDefaults(axLayoutIn, axLayoutOut, coerce, {
96297
- allAxisIds: allAxisIds,
96454
+ allAxisIds: allAxisIdsIncludingMissing,
96298
96455
  layoutOut: layoutOut,
96299
96456
  scaleanchorDflt: scaleanchorDflt,
96300
96457
  constrainDflt: constrainDflt
@@ -96305,7 +96462,6 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
96305
96462
  var group = matchGroups[i];
96306
96463
  var rng = null;
96307
96464
  var autorange = null;
96308
- var axId;
96309
96465
 
96310
96466
  // find 'matching' range attrs
96311
96467
  for(axId in group) {
@@ -96358,7 +96514,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
96358
96514
  }
96359
96515
  };
96360
96516
 
96361
- },{"../../components/color":376,"../../lib":496,"../../plot_api/plot_template":532,"../../registry":594,"../layout_attributes":583,"./axis_defaults":544,"./axis_ids":545,"./constraints":549,"./layout_attributes":554,"./position_defaults":557,"./type_defaults":565}],556:[function(_dereq_,module,exports){
96517
+ },{"../../components/color":376,"../../lib":496,"../../plot_api/plot_template":532,"../../registry":594,"../layout_attributes":583,"./axis_defaults":544,"./axis_ids":545,"./constants":548,"./constraints":549,"./layout_attributes":554,"./position_defaults":557,"./type_defaults":565}],556:[function(_dereq_,module,exports){
96362
96518
  /**
96363
96519
  * Copyright 2012-2020, Plotly, Inc.
96364
96520
  * All rights reserved.
@@ -100400,177 +100556,108 @@ var createAxesOptions = _dereq_('./layout/convert');
100400
100556
  var createSpikeOptions = _dereq_('./layout/spikes');
100401
100557
  var computeTickMarks = _dereq_('./layout/tick_marks');
100402
100558
 
100559
+ var isMobile = _dereq_('is-mobile');
100560
+ var tablet = isTablet();
100403
100561
 
100404
- var STATIC_CANVAS, STATIC_CONTEXT;
100405
-
100406
- function render(scene) {
100407
- var gd = scene.graphDiv;
100408
- var trace;
100562
+ function isTablet() {
100563
+ if(!navigator) return false;
100409
100564
 
100410
- // update size of svg container
100411
- var svgContainer = scene.svgContainer;
100412
- var clientRect = scene.container.getBoundingClientRect();
100413
- var width = clientRect.width;
100414
- var height = clientRect.height;
100415
- svgContainer.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);
100416
- svgContainer.setAttributeNS(null, 'width', width);
100417
- svgContainer.setAttributeNS(null, 'height', height);
100418
-
100419
- computeTickMarks(scene);
100420
- scene.glplot.axes.update(scene.axesOptions);
100421
-
100422
- // check if pick has changed
100423
- var keys = Object.keys(scene.traces);
100424
- var lastPicked = null;
100425
- var selection = scene.glplot.selection;
100426
- for(var i = 0; i < keys.length; ++i) {
100427
- trace = scene.traces[keys[i]];
100428
- if(trace.data.hoverinfo !== 'skip' && trace.handlePick(selection)) {
100429
- lastPicked = trace;
100430
- }
100431
-
100432
- if(trace.setContourLevels) trace.setContourLevels();
100565
+ var ua;
100566
+ // same interface as applied by is-mobile module
100567
+ if(!ua && typeof navigator !== 'undefined') ua = navigator.userAgent;
100568
+ if(ua && ua.headers && typeof ua.headers['user-agent'] === 'string') {
100569
+ ua = ua.headers['user-agent'];
100433
100570
  }
100571
+ if(typeof ua !== 'string') return false;
100434
100572
 
100435
- function formatter(axisName, val) {
100436
- var axis = scene.fullSceneLayout[axisName];
100573
+ var result = isMobile({
100574
+ ua: ua,
100575
+ tablet: true
100576
+ });
100437
100577
 
100438
- return Axes.tickText(axis, axis.d2l(val), 'hover').text;
100578
+ // handle iPad pro or iPad with iOs 13 using Safari
100579
+ // see https://github.com/plotly/plotly.js/issues/4502
100580
+ if(
100581
+ result === false &&
100582
+ ua.indexOf('Macintosh') !== -1 &&
100583
+ ua.indexOf('Safari') !== -1 &&
100584
+ navigator.maxTouchPoints > 1
100585
+ ) {
100586
+ result = true;
100439
100587
  }
100440
100588
 
100441
- var oldEventData;
100442
-
100443
- if(lastPicked !== null) {
100444
- var pdata = project(scene.glplot.cameraParams, selection.dataCoordinate);
100445
- trace = lastPicked.data;
100446
- var traceNow = gd._fullData[trace.index];
100447
- var ptNumber = selection.index;
100448
-
100449
- var labels = {
100450
- xLabel: formatter('xaxis', selection.traceCoordinate[0]),
100451
- yLabel: formatter('yaxis', selection.traceCoordinate[1]),
100452
- zLabel: formatter('zaxis', selection.traceCoordinate[2])
100453
- };
100454
-
100455
- var hoverinfo = Fx.castHoverinfo(traceNow, scene.fullLayout, ptNumber);
100456
- var hoverinfoParts = (hoverinfo || '').split('+');
100457
- var isHoverinfoAll = hoverinfo && hoverinfo === 'all';
100458
-
100459
- if(!traceNow.hovertemplate && !isHoverinfoAll) {
100460
- if(hoverinfoParts.indexOf('x') === -1) labels.xLabel = undefined;
100461
- if(hoverinfoParts.indexOf('y') === -1) labels.yLabel = undefined;
100462
- if(hoverinfoParts.indexOf('z') === -1) labels.zLabel = undefined;
100463
- if(hoverinfoParts.indexOf('text') === -1) selection.textLabel = undefined;
100464
- if(hoverinfoParts.indexOf('name') === -1) lastPicked.name = undefined;
100465
- }
100589
+ return result;
100590
+ }
100466
100591
 
100467
- var tx;
100468
- var vectorTx = [];
100469
100592
 
100470
- if(trace.type === 'cone' || trace.type === 'streamtube') {
100471
- labels.uLabel = formatter('xaxis', selection.traceCoordinate[3]);
100472
- if(isHoverinfoAll || hoverinfoParts.indexOf('u') !== -1) {
100473
- vectorTx.push('u: ' + labels.uLabel);
100474
- }
100593
+ var STATIC_CANVAS, STATIC_CONTEXT;
100475
100594
 
100476
- labels.vLabel = formatter('yaxis', selection.traceCoordinate[4]);
100477
- if(isHoverinfoAll || hoverinfoParts.indexOf('v') !== -1) {
100478
- vectorTx.push('v: ' + labels.vLabel);
100479
- }
100595
+ function Scene(options, fullLayout) {
100596
+ // create sub container for plot
100597
+ var sceneContainer = document.createElement('div');
100598
+ var plotContainer = options.container;
100480
100599
 
100481
- labels.wLabel = formatter('zaxis', selection.traceCoordinate[5]);
100482
- if(isHoverinfoAll || hoverinfoParts.indexOf('w') !== -1) {
100483
- vectorTx.push('w: ' + labels.wLabel);
100484
- }
100600
+ // keep a ref to the graph div to fire hover+click events
100601
+ this.graphDiv = options.graphDiv;
100485
100602
 
100486
- labels.normLabel = selection.traceCoordinate[6].toPrecision(3);
100487
- if(isHoverinfoAll || hoverinfoParts.indexOf('norm') !== -1) {
100488
- vectorTx.push('norm: ' + labels.normLabel);
100489
- }
100490
- if(trace.type === 'streamtube') {
100491
- labels.divergenceLabel = selection.traceCoordinate[7].toPrecision(3);
100492
- if(isHoverinfoAll || hoverinfoParts.indexOf('divergence') !== -1) {
100493
- vectorTx.push('divergence: ' + labels.divergenceLabel);
100494
- }
100495
- }
100496
- if(selection.textLabel) {
100497
- vectorTx.push(selection.textLabel);
100498
- }
100499
- tx = vectorTx.join('<br>');
100500
- } else if(trace.type === 'isosurface' || trace.type === 'volume') {
100501
- labels.valueLabel = Axes.tickText(scene.mockAxis, scene.mockAxis.d2l(selection.traceCoordinate[3]), 'hover').text;
100502
- vectorTx.push('value: ' + labels.valueLabel);
100503
- if(selection.textLabel) {
100504
- vectorTx.push(selection.textLabel);
100505
- }
100506
- tx = vectorTx.join('<br>');
100507
- } else {
100508
- tx = selection.textLabel;
100509
- }
100603
+ // create SVG container for hover text
100604
+ var svgContainer = document.createElementNS(
100605
+ 'http://www.w3.org/2000/svg',
100606
+ 'svg');
100607
+ svgContainer.style.position = 'absolute';
100608
+ svgContainer.style.top = svgContainer.style.left = '0px';
100609
+ svgContainer.style.width = svgContainer.style.height = '100%';
100610
+ svgContainer.style['z-index'] = 20;
100611
+ svgContainer.style['pointer-events'] = 'none';
100612
+ sceneContainer.appendChild(svgContainer);
100613
+ this.svgContainer = svgContainer;
100510
100614
 
100511
- var pointData = {
100512
- x: selection.traceCoordinate[0],
100513
- y: selection.traceCoordinate[1],
100514
- z: selection.traceCoordinate[2],
100515
- data: traceNow._input,
100516
- fullData: traceNow,
100517
- curveNumber: traceNow.index,
100518
- pointNumber: ptNumber
100519
- };
100615
+ // Tag the container with the sceneID
100616
+ sceneContainer.id = options.id;
100617
+ sceneContainer.style.position = 'absolute';
100618
+ sceneContainer.style.top = sceneContainer.style.left = '0px';
100619
+ sceneContainer.style.width = sceneContainer.style.height = '100%';
100620
+ plotContainer.appendChild(sceneContainer);
100520
100621
 
100521
- Fx.appendArrayPointValue(pointData, traceNow, ptNumber);
100622
+ this.fullLayout = fullLayout;
100623
+ this.id = options.id || 'scene';
100624
+ this.fullSceneLayout = fullLayout[this.id];
100522
100625
 
100523
- if(trace._module.eventData) {
100524
- pointData = traceNow._module.eventData(pointData, selection, traceNow, {}, ptNumber);
100525
- }
100626
+ // Saved from last call to plot()
100627
+ this.plotArgs = [ [], {}, {} ];
100526
100628
 
100527
- var eventData = {points: [pointData]};
100629
+ /*
100630
+ * Move this to calc step? Why does it work here?
100631
+ */
100632
+ this.axesOptions = createAxesOptions(fullLayout, fullLayout[this.id]);
100633
+ this.spikeOptions = createSpikeOptions(fullLayout[this.id]);
100634
+ this.container = sceneContainer;
100635
+ this.staticMode = !!options.staticPlot;
100636
+ this.pixelRatio = this.pixelRatio || options.plotGlPixelRatio || 2;
100528
100637
 
100529
- if(scene.fullSceneLayout.hovermode) {
100530
- Fx.loneHover({
100531
- trace: traceNow,
100532
- x: (0.5 + 0.5 * pdata[0] / pdata[3]) * width,
100533
- y: (0.5 - 0.5 * pdata[1] / pdata[3]) * height,
100534
- xLabel: labels.xLabel,
100535
- yLabel: labels.yLabel,
100536
- zLabel: labels.zLabel,
100537
- text: tx,
100538
- name: lastPicked.name,
100539
- color: Fx.castHoverOption(traceNow, ptNumber, 'bgcolor') || lastPicked.color,
100540
- borderColor: Fx.castHoverOption(traceNow, ptNumber, 'bordercolor'),
100541
- fontFamily: Fx.castHoverOption(traceNow, ptNumber, 'font.family'),
100542
- fontSize: Fx.castHoverOption(traceNow, ptNumber, 'font.size'),
100543
- fontColor: Fx.castHoverOption(traceNow, ptNumber, 'font.color'),
100544
- nameLength: Fx.castHoverOption(traceNow, ptNumber, 'namelength'),
100545
- textAlign: Fx.castHoverOption(traceNow, ptNumber, 'align'),
100546
- hovertemplate: Lib.castOption(traceNow, ptNumber, 'hovertemplate'),
100547
- hovertemplateLabels: Lib.extendFlat({}, pointData, labels),
100548
- eventData: [pointData]
100549
- }, {
100550
- container: svgContainer,
100551
- gd: gd
100552
- });
100553
- }
100638
+ // Coordinate rescaling
100639
+ this.dataScale = [1, 1, 1];
100554
100640
 
100555
- if(selection.buttons && selection.distance < 5) {
100556
- gd.emit('plotly_click', eventData);
100557
- } else {
100558
- gd.emit('plotly_hover', eventData);
100559
- }
100641
+ this.contourLevels = [ [], [], [] ];
100560
100642
 
100561
- oldEventData = eventData;
100562
- } else {
100563
- Fx.loneUnhover(svgContainer);
100564
- gd.emit('plotly_unhover', oldEventData);
100565
- }
100643
+ this.convertAnnotations = Registry.getComponentMethod('annotations3d', 'convert');
100644
+ this.drawAnnotations = Registry.getComponentMethod('annotations3d', 'draw');
100566
100645
 
100567
- scene.drawAnnotations(scene);
100646
+ this.initializeGLPlot();
100568
100647
  }
100569
100648
 
100570
- function tryCreatePlot(scene, cameraObject, pixelRatio, canvas, gl) {
100571
- var glplotOptions = {
100572
- canvas: canvas,
100573
- gl: gl,
100649
+ var proto = Scene.prototype;
100650
+
100651
+ proto.tryCreatePlot = function() {
100652
+ var scene = this;
100653
+ var opts = {
100654
+ canvas: scene.canvas,
100655
+ gl: scene.gl,
100656
+ glOptions: {
100657
+ preserveDrawingBuffer: tablet,
100658
+ premultipliedAlpha: true,
100659
+ antialias: true
100660
+ },
100574
100661
  container: scene.container,
100575
100662
  axes: scene.axesOptions,
100576
100663
  spikes: scene.spikeOptions,
@@ -100578,8 +100665,8 @@ function tryCreatePlot(scene, cameraObject, pixelRatio, canvas, gl) {
100578
100665
  snapToData: true,
100579
100666
  autoScale: true,
100580
100667
  autoBounds: false,
100581
- cameraObject: cameraObject,
100582
- pixelRatio: pixelRatio
100668
+ cameraObject: scene.camera,
100669
+ pixelRatio: scene.pixelRatio
100583
100670
  };
100584
100671
 
100585
100672
  // for static plots, we reuse the WebGL context
@@ -100597,31 +100684,49 @@ function tryCreatePlot(scene, cameraObject, pixelRatio, canvas, gl) {
100597
100684
  throw new Error('error creating static canvas/context for image server');
100598
100685
  }
100599
100686
  }
100600
- glplotOptions.pixelRatio = scene.pixelRatio;
100601
- glplotOptions.gl = STATIC_CONTEXT;
100602
- glplotOptions.canvas = STATIC_CANVAS;
100687
+
100688
+ opts.gl = STATIC_CONTEXT;
100689
+ opts.canvas = STATIC_CANVAS;
100603
100690
  }
100604
100691
 
100605
100692
  var failed = 0;
100606
100693
 
100607
100694
  try {
100608
- scene.glplot = createPlot(glplotOptions);
100695
+ scene.glplot = createPlot(opts);
100609
100696
  } catch(e) {
100610
100697
  failed++;
100611
100698
  try { // try second time to fix issue with Chrome 77 https://github.com/plotly/plotly.js/issues/4233
100612
- scene.glplot = createPlot(glplotOptions);
100699
+ scene.glplot = createPlot(opts);
100613
100700
  } catch(e) {
100614
100701
  failed++;
100615
100702
  }
100616
100703
  }
100617
100704
 
100618
100705
  return failed < 2;
100619
- }
100706
+ };
100707
+
100708
+ proto.initializeGLCamera = function() {
100709
+ var scene = this;
100710
+ var cameraData = scene.fullSceneLayout.camera;
100711
+ var isOrtho = (cameraData.projection.type === 'orthographic');
100712
+
100713
+ scene.camera = createCamera(scene.container, {
100714
+ center: [cameraData.center.x, cameraData.center.y, cameraData.center.z],
100715
+ eye: [cameraData.eye.x, cameraData.eye.y, cameraData.eye.z],
100716
+ up: [cameraData.up.x, cameraData.up.y, cameraData.up.z],
100717
+ _ortho: isOrtho,
100718
+ zoomMin: 0.01,
100719
+ zoomMax: 100,
100720
+ mode: 'orbit'
100721
+ });
100722
+ };
100723
+
100724
+ proto.initializeGLPlot = function() {
100725
+ var scene = this;
100620
100726
 
100621
- function initializeGLPlot(scene, canvas, gl) {
100622
100727
  scene.initializeGLCamera();
100623
100728
 
100624
- var success = tryCreatePlot(scene, scene.camera, scene.pixelRatio, canvas, gl);
100729
+ var success = scene.tryCreatePlot();
100625
100730
  /*
100626
100731
  * createPlot will throw when webgl is not enabled in the client.
100627
100732
  * Lets return an instance of the module with all functions noop'd.
@@ -100630,6 +100735,11 @@ function initializeGLPlot(scene, canvas, gl) {
100630
100735
  */
100631
100736
  if(!success) return showNoWebGlMsg(scene);
100632
100737
 
100738
+ // List of scene objects
100739
+ scene.traces = {};
100740
+
100741
+ scene.make4thDimension();
100742
+
100633
100743
  var gd = scene.graphDiv;
100634
100744
  var layout = gd.layout;
100635
100745
 
@@ -100663,7 +100773,7 @@ function initializeGLPlot(scene, canvas, gl) {
100663
100773
 
100664
100774
  scene.glplot.canvas.addEventListener('wheel', function(e) {
100665
100775
  if(gd._context._scrollZoom.gl3d) {
100666
- if(scene.glplot.camera._ortho) {
100776
+ if(scene.camera._ortho) {
100667
100777
  var s = (e.deltaX > e.deltaY) ? 1.1 : 1.0 / 1.1;
100668
100778
  var o = scene.glplot.getAspectratio();
100669
100779
  scene.glplot.setAspectratio({
@@ -100696,111 +100806,199 @@ function initializeGLPlot(scene, canvas, gl) {
100696
100806
  }, false);
100697
100807
  }
100698
100808
 
100699
- scene.glplot.camera = scene.camera;
100700
-
100701
100809
  scene.glplot.oncontextloss = function() {
100702
100810
  scene.recoverContext();
100703
100811
  };
100704
100812
 
100705
- scene.glplot.onrender = render.bind(null, scene);
100813
+ scene.glplot.onrender = function() {
100814
+ scene.render();
100815
+ };
100706
100816
 
100707
- // List of scene objects
100708
- scene.traces = {};
100817
+ return true;
100818
+ };
100709
100819
 
100710
- scene.make4thDimension();
100820
+ proto.render = function() {
100821
+ var scene = this;
100822
+ var gd = scene.graphDiv;
100823
+ var trace;
100711
100824
 
100712
- return true;
100713
- }
100825
+ // update size of svg container
100826
+ var svgContainer = scene.svgContainer;
100827
+ var clientRect = scene.container.getBoundingClientRect();
100828
+ var width = clientRect.width;
100829
+ var height = clientRect.height;
100830
+ svgContainer.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);
100831
+ svgContainer.setAttributeNS(null, 'width', width);
100832
+ svgContainer.setAttributeNS(null, 'height', height);
100714
100833
 
100715
- function Scene(options, fullLayout) {
100716
- // create sub container for plot
100717
- var sceneContainer = document.createElement('div');
100718
- var plotContainer = options.container;
100834
+ computeTickMarks(scene);
100835
+ scene.glplot.axes.update(scene.axesOptions);
100719
100836
 
100720
- // keep a ref to the graph div to fire hover+click events
100721
- this.graphDiv = options.graphDiv;
100837
+ // check if pick has changed
100838
+ var keys = Object.keys(scene.traces);
100839
+ var lastPicked = null;
100840
+ var selection = scene.glplot.selection;
100841
+ for(var i = 0; i < keys.length; ++i) {
100842
+ trace = scene.traces[keys[i]];
100843
+ if(trace.data.hoverinfo !== 'skip' && trace.handlePick(selection)) {
100844
+ lastPicked = trace;
100845
+ }
100722
100846
 
100723
- // create SVG container for hover text
100724
- var svgContainer = document.createElementNS(
100725
- 'http://www.w3.org/2000/svg',
100726
- 'svg');
100727
- svgContainer.style.position = 'absolute';
100728
- svgContainer.style.top = svgContainer.style.left = '0px';
100729
- svgContainer.style.width = svgContainer.style.height = '100%';
100730
- svgContainer.style['z-index'] = 20;
100731
- svgContainer.style['pointer-events'] = 'none';
100732
- sceneContainer.appendChild(svgContainer);
100733
- this.svgContainer = svgContainer;
100847
+ if(trace.setContourLevels) trace.setContourLevels();
100848
+ }
100734
100849
 
100735
- // Tag the container with the sceneID
100736
- sceneContainer.id = options.id;
100737
- sceneContainer.style.position = 'absolute';
100738
- sceneContainer.style.top = sceneContainer.style.left = '0px';
100739
- sceneContainer.style.width = sceneContainer.style.height = '100%';
100740
- plotContainer.appendChild(sceneContainer);
100850
+ function formatter(axisName, val) {
100851
+ var axis = scene.fullSceneLayout[axisName];
100741
100852
 
100742
- this.fullLayout = fullLayout;
100743
- this.id = options.id || 'scene';
100744
- this.fullSceneLayout = fullLayout[this.id];
100853
+ return Axes.tickText(axis, axis.d2l(val), 'hover').text;
100854
+ }
100745
100855
 
100746
- // Saved from last call to plot()
100747
- this.plotArgs = [ [], {}, {} ];
100856
+ var oldEventData;
100748
100857
 
100749
- /*
100750
- * Move this to calc step? Why does it work here?
100751
- */
100752
- this.axesOptions = createAxesOptions(fullLayout, fullLayout[this.id]);
100753
- this.spikeOptions = createSpikeOptions(fullLayout[this.id]);
100754
- this.container = sceneContainer;
100755
- this.staticMode = !!options.staticPlot;
100756
- this.pixelRatio = this.pixelRatio || options.plotGlPixelRatio || 2;
100858
+ if(lastPicked !== null) {
100859
+ var pdata = project(scene.glplot.cameraParams, selection.dataCoordinate);
100860
+ trace = lastPicked.data;
100861
+ var traceNow = gd._fullData[trace.index];
100862
+ var ptNumber = selection.index;
100757
100863
 
100758
- // Coordinate rescaling
100759
- this.dataScale = [1, 1, 1];
100864
+ var labels = {
100865
+ xLabel: formatter('xaxis', selection.traceCoordinate[0]),
100866
+ yLabel: formatter('yaxis', selection.traceCoordinate[1]),
100867
+ zLabel: formatter('zaxis', selection.traceCoordinate[2])
100868
+ };
100760
100869
 
100761
- this.contourLevels = [ [], [], [] ];
100870
+ var hoverinfo = Fx.castHoverinfo(traceNow, scene.fullLayout, ptNumber);
100871
+ var hoverinfoParts = (hoverinfo || '').split('+');
100872
+ var isHoverinfoAll = hoverinfo && hoverinfo === 'all';
100762
100873
 
100763
- this.convertAnnotations = Registry.getComponentMethod('annotations3d', 'convert');
100764
- this.drawAnnotations = Registry.getComponentMethod('annotations3d', 'draw');
100874
+ if(!traceNow.hovertemplate && !isHoverinfoAll) {
100875
+ if(hoverinfoParts.indexOf('x') === -1) labels.xLabel = undefined;
100876
+ if(hoverinfoParts.indexOf('y') === -1) labels.yLabel = undefined;
100877
+ if(hoverinfoParts.indexOf('z') === -1) labels.zLabel = undefined;
100878
+ if(hoverinfoParts.indexOf('text') === -1) selection.textLabel = undefined;
100879
+ if(hoverinfoParts.indexOf('name') === -1) lastPicked.name = undefined;
100880
+ }
100765
100881
 
100766
- initializeGLPlot(this);
100767
- }
100882
+ var tx;
100883
+ var vectorTx = [];
100768
100884
 
100769
- var proto = Scene.prototype;
100885
+ if(trace.type === 'cone' || trace.type === 'streamtube') {
100886
+ labels.uLabel = formatter('xaxis', selection.traceCoordinate[3]);
100887
+ if(isHoverinfoAll || hoverinfoParts.indexOf('u') !== -1) {
100888
+ vectorTx.push('u: ' + labels.uLabel);
100889
+ }
100770
100890
 
100771
- proto.initializeGLCamera = function() {
100772
- var cameraData = this.fullSceneLayout.camera;
100773
- var isOrtho = (cameraData.projection.type === 'orthographic');
100891
+ labels.vLabel = formatter('yaxis', selection.traceCoordinate[4]);
100892
+ if(isHoverinfoAll || hoverinfoParts.indexOf('v') !== -1) {
100893
+ vectorTx.push('v: ' + labels.vLabel);
100894
+ }
100774
100895
 
100775
- this.camera = createCamera(this.container, {
100776
- center: [cameraData.center.x, cameraData.center.y, cameraData.center.z],
100777
- eye: [cameraData.eye.x, cameraData.eye.y, cameraData.eye.z],
100778
- up: [cameraData.up.x, cameraData.up.y, cameraData.up.z],
100779
- _ortho: isOrtho,
100780
- zoomMin: 0.01,
100781
- zoomMax: 100,
100782
- mode: 'orbit'
100783
- });
100896
+ labels.wLabel = formatter('zaxis', selection.traceCoordinate[5]);
100897
+ if(isHoverinfoAll || hoverinfoParts.indexOf('w') !== -1) {
100898
+ vectorTx.push('w: ' + labels.wLabel);
100899
+ }
100900
+
100901
+ labels.normLabel = selection.traceCoordinate[6].toPrecision(3);
100902
+ if(isHoverinfoAll || hoverinfoParts.indexOf('norm') !== -1) {
100903
+ vectorTx.push('norm: ' + labels.normLabel);
100904
+ }
100905
+ if(trace.type === 'streamtube') {
100906
+ labels.divergenceLabel = selection.traceCoordinate[7].toPrecision(3);
100907
+ if(isHoverinfoAll || hoverinfoParts.indexOf('divergence') !== -1) {
100908
+ vectorTx.push('divergence: ' + labels.divergenceLabel);
100909
+ }
100910
+ }
100911
+ if(selection.textLabel) {
100912
+ vectorTx.push(selection.textLabel);
100913
+ }
100914
+ tx = vectorTx.join('<br>');
100915
+ } else if(trace.type === 'isosurface' || trace.type === 'volume') {
100916
+ labels.valueLabel = Axes.tickText(scene._mockAxis, scene._mockAxis.d2l(selection.traceCoordinate[3]), 'hover').text;
100917
+ vectorTx.push('value: ' + labels.valueLabel);
100918
+ if(selection.textLabel) {
100919
+ vectorTx.push(selection.textLabel);
100920
+ }
100921
+ tx = vectorTx.join('<br>');
100922
+ } else {
100923
+ tx = selection.textLabel;
100924
+ }
100925
+
100926
+ var pointData = {
100927
+ x: selection.traceCoordinate[0],
100928
+ y: selection.traceCoordinate[1],
100929
+ z: selection.traceCoordinate[2],
100930
+ data: traceNow._input,
100931
+ fullData: traceNow,
100932
+ curveNumber: traceNow.index,
100933
+ pointNumber: ptNumber
100934
+ };
100935
+
100936
+ Fx.appendArrayPointValue(pointData, traceNow, ptNumber);
100937
+
100938
+ if(trace._module.eventData) {
100939
+ pointData = traceNow._module.eventData(pointData, selection, traceNow, {}, ptNumber);
100940
+ }
100941
+
100942
+ var eventData = {points: [pointData]};
100943
+
100944
+ if(scene.fullSceneLayout.hovermode) {
100945
+ Fx.loneHover({
100946
+ trace: traceNow,
100947
+ x: (0.5 + 0.5 * pdata[0] / pdata[3]) * width,
100948
+ y: (0.5 - 0.5 * pdata[1] / pdata[3]) * height,
100949
+ xLabel: labels.xLabel,
100950
+ yLabel: labels.yLabel,
100951
+ zLabel: labels.zLabel,
100952
+ text: tx,
100953
+ name: lastPicked.name,
100954
+ color: Fx.castHoverOption(traceNow, ptNumber, 'bgcolor') || lastPicked.color,
100955
+ borderColor: Fx.castHoverOption(traceNow, ptNumber, 'bordercolor'),
100956
+ fontFamily: Fx.castHoverOption(traceNow, ptNumber, 'font.family'),
100957
+ fontSize: Fx.castHoverOption(traceNow, ptNumber, 'font.size'),
100958
+ fontColor: Fx.castHoverOption(traceNow, ptNumber, 'font.color'),
100959
+ nameLength: Fx.castHoverOption(traceNow, ptNumber, 'namelength'),
100960
+ textAlign: Fx.castHoverOption(traceNow, ptNumber, 'align'),
100961
+ hovertemplate: Lib.castOption(traceNow, ptNumber, 'hovertemplate'),
100962
+ hovertemplateLabels: Lib.extendFlat({}, pointData, labels),
100963
+ eventData: [pointData]
100964
+ }, {
100965
+ container: svgContainer,
100966
+ gd: gd
100967
+ });
100968
+ }
100969
+
100970
+ if(selection.buttons && selection.distance < 5) {
100971
+ gd.emit('plotly_click', eventData);
100972
+ } else {
100973
+ gd.emit('plotly_hover', eventData);
100974
+ }
100975
+
100976
+ oldEventData = eventData;
100977
+ } else {
100978
+ Fx.loneUnhover(svgContainer);
100979
+ gd.emit('plotly_unhover', oldEventData);
100980
+ }
100981
+
100982
+ scene.drawAnnotations(scene);
100784
100983
  };
100785
100984
 
100786
100985
  proto.recoverContext = function() {
100787
100986
  var scene = this;
100788
- var gl = this.glplot.gl;
100789
- var canvas = this.glplot.canvas;
100790
100987
 
100791
- this.glplot.dispose();
100988
+ scene.glplot.dispose();
100792
100989
 
100793
- function tryRecover() {
100794
- if(gl.isContextLost()) {
100990
+ var tryRecover = function() {
100991
+ if(scene.glplot.gl.isContextLost()) {
100795
100992
  requestAnimationFrame(tryRecover);
100796
100993
  return;
100797
100994
  }
100798
- if(!initializeGLPlot(scene, canvas, gl)) {
100995
+ if(!scene.initializeGLPlot()) {
100799
100996
  Lib.error('Catastrophic and unrecoverable WebGL error. Context lost.');
100800
100997
  return;
100801
100998
  }
100802
100999
  scene.plot.apply(scene, scene.plotArgs);
100803
- }
101000
+ };
101001
+
100804
101002
  requestAnimationFrame(tryRecover);
100805
101003
  };
100806
101004
 
@@ -100868,39 +101066,35 @@ function computeAnnotationBounds(scene, bounds) {
100868
101066
  }
100869
101067
 
100870
101068
  proto.plot = function(sceneData, fullLayout, layout) {
101069
+ var scene = this;
101070
+
100871
101071
  // Save parameters
100872
- this.plotArgs = [sceneData, fullLayout, layout];
101072
+ scene.plotArgs = [sceneData, fullLayout, layout];
100873
101073
 
100874
- if(this.glplot.contextLost) return;
101074
+ if(scene.glplot.contextLost) return;
100875
101075
 
100876
101076
  var data, trace;
100877
101077
  var i, j, axis, axisType;
100878
- var fullSceneLayout = fullLayout[this.id];
100879
- var sceneLayout = layout[this.id];
100880
-
100881
- if(fullSceneLayout.bgcolor) this.glplot.clearColor = str2RGBAarray(fullSceneLayout.bgcolor);
100882
- else this.glplot.clearColor = [0, 0, 0, 0];
100883
-
100884
- this.glplot.snapToData = true;
101078
+ var fullSceneLayout = fullLayout[scene.id];
101079
+ var sceneLayout = layout[scene.id];
100885
101080
 
100886
101081
  // Update layout
100887
- this.fullLayout = fullLayout;
100888
- this.fullSceneLayout = fullSceneLayout;
101082
+ scene.fullLayout = fullLayout;
101083
+ scene.fullSceneLayout = fullSceneLayout;
100889
101084
 
100890
- this.glplotLayout = fullSceneLayout;
100891
- this.axesOptions.merge(fullLayout, fullSceneLayout);
100892
- this.spikeOptions.merge(fullSceneLayout);
101085
+ scene.axesOptions.merge(fullLayout, fullSceneLayout);
101086
+ scene.spikeOptions.merge(fullSceneLayout);
100893
101087
 
100894
101088
  // Update camera and camera mode
100895
- this.setViewport(fullSceneLayout);
100896
- this.updateFx(fullSceneLayout.dragmode, fullSceneLayout.hovermode);
100897
- this.camera.enableWheel = this.graphDiv._context._scrollZoom.gl3d;
101089
+ scene.setViewport(fullSceneLayout);
101090
+ scene.updateFx(fullSceneLayout.dragmode, fullSceneLayout.hovermode);
101091
+ scene.camera.enableWheel = scene.graphDiv._context._scrollZoom.gl3d;
100898
101092
 
100899
- // Update scene
100900
- this.glplot.update({});
101093
+ // Update scene background
101094
+ scene.glplot.setClearColor(str2RGBAarray(fullSceneLayout.bgcolor));
100901
101095
 
100902
101096
  // Update axes functions BEFORE updating traces
100903
- this.setConvert(axis);
101097
+ scene.setConvert(axis);
100904
101098
 
100905
101099
  // Convert scene data
100906
101100
  if(!sceneData) sceneData = [];
@@ -100930,10 +101124,10 @@ proto.plot = function(sceneData, fullLayout, layout) {
100930
101124
  }
100931
101125
 
100932
101126
  // Save scale
100933
- this.dataScale = dataScale;
101127
+ scene.dataScale = dataScale;
100934
101128
 
100935
101129
  // after computeTraceBounds where ax._categories are filled in
100936
- this.convertAnnotations(this);
101130
+ scene.convertAnnotations(this);
100937
101131
 
100938
101132
  // Update traces
100939
101133
  for(i = 0; i < sceneData.length; ++i) {
@@ -100941,24 +101135,24 @@ proto.plot = function(sceneData, fullLayout, layout) {
100941
101135
  if(data.visible !== true || data._length === 0) {
100942
101136
  continue;
100943
101137
  }
100944
- trace = this.traces[data.uid];
101138
+ trace = scene.traces[data.uid];
100945
101139
  if(trace) {
100946
101140
  if(trace.data.type === data.type) {
100947
101141
  trace.update(data);
100948
101142
  } else {
100949
101143
  trace.dispose();
100950
101144
  trace = data._module.plot(this, data);
100951
- this.traces[data.uid] = trace;
101145
+ scene.traces[data.uid] = trace;
100952
101146
  }
100953
101147
  } else {
100954
101148
  trace = data._module.plot(this, data);
100955
- this.traces[data.uid] = trace;
101149
+ scene.traces[data.uid] = trace;
100956
101150
  }
100957
101151
  trace.name = data.name;
100958
101152
  }
100959
101153
 
100960
101154
  // Remove empty traces
100961
- var traceIds = Object.keys(this.traces);
101155
+ var traceIds = Object.keys(scene.traces);
100962
101156
 
100963
101157
  traceIdLoop:
100964
101158
  for(i = 0; i < traceIds.length; ++i) {
@@ -100968,13 +101162,13 @@ proto.plot = function(sceneData, fullLayout, layout) {
100968
101162
  continue traceIdLoop;
100969
101163
  }
100970
101164
  }
100971
- trace = this.traces[traceIds[i]];
101165
+ trace = scene.traces[traceIds[i]];
100972
101166
  trace.dispose();
100973
- delete this.traces[traceIds[i]];
101167
+ delete scene.traces[traceIds[i]];
100974
101168
  }
100975
101169
 
100976
101170
  // order object per trace index
100977
- this.glplot.objects.sort(function(a, b) {
101171
+ scene.glplot.objects.sort(function(a, b) {
100978
101172
  return a._trace.data.index - b._trace.data.index;
100979
101173
  });
100980
101174
 
@@ -101001,8 +101195,8 @@ proto.plot = function(sceneData, fullLayout, layout) {
101001
101195
  sceneBounds[0][i] = Infinity;
101002
101196
  sceneBounds[1][i] = -Infinity;
101003
101197
 
101004
- var objects = this.glplot.objects;
101005
- var annotations = this.fullSceneLayout.annotations || [];
101198
+ var objects = scene.glplot.objects;
101199
+ var annotations = scene.fullSceneLayout.annotations || [];
101006
101200
  var axLetter = axis._name.charAt(0);
101007
101201
 
101008
101202
  for(j = 0; j < objects.length; j++) {
@@ -101060,8 +101254,10 @@ proto.plot = function(sceneData, fullLayout, layout) {
101060
101254
  axisDataRange[i] = sceneBounds[1][i] - sceneBounds[0][i];
101061
101255
 
101062
101256
  // Update plot bounds
101063
- this.glplot.bounds[0][i] = sceneBounds[0][i] * dataScale[i];
101064
- this.glplot.bounds[1][i] = sceneBounds[1][i] * dataScale[i];
101257
+ scene.glplot.setBounds(i, {
101258
+ min: sceneBounds[0][i] * dataScale[i],
101259
+ max: sceneBounds[1][i] * dataScale[i]
101260
+ });
101065
101261
  }
101066
101262
 
101067
101263
  var axesScaleRatio = [1, 1, 1];
@@ -101116,11 +101312,11 @@ proto.plot = function(sceneData, fullLayout, layout) {
101116
101312
  * Finally assign the computed aspecratio to the glplot module. This will have an effect
101117
101313
  * on the next render cycle.
101118
101314
  */
101119
- this.glplot.setAspectratio(fullSceneLayout.aspectratio);
101315
+ scene.glplot.setAspectratio(fullSceneLayout.aspectratio);
101120
101316
 
101121
101317
  // save 'initial' camera view settings for modebar button
101122
- if(!this.viewInitial.aspectratio) {
101123
- this.viewInitial.aspectratio = {
101318
+ if(!scene.viewInitial.aspectratio) {
101319
+ scene.viewInitial.aspectratio = {
101124
101320
  x: fullSceneLayout.aspectratio.x,
101125
101321
  y: fullSceneLayout.aspectratio.y,
101126
101322
  z: fullSceneLayout.aspectratio.z
@@ -101132,7 +101328,7 @@ proto.plot = function(sceneData, fullLayout, layout) {
101132
101328
  var size = fullLayout._size || null;
101133
101329
 
101134
101330
  if(domain && size) {
101135
- var containerStyle = this.container.style;
101331
+ var containerStyle = scene.container.style;
101136
101332
  containerStyle.position = 'absolute';
101137
101333
  containerStyle.left = (size.l + domain.x[0] * size.w) + 'px';
101138
101334
  containerStyle.top = (size.t + (1 - domain.y[1]) * size.h) + 'px';
@@ -101141,18 +101337,19 @@ proto.plot = function(sceneData, fullLayout, layout) {
101141
101337
  }
101142
101338
 
101143
101339
  // force redraw so that promise is returned when rendering is completed
101144
- this.glplot.redraw();
101340
+ scene.glplot.redraw();
101145
101341
  };
101146
101342
 
101147
101343
  proto.destroy = function() {
101148
- if(!this.glplot) return;
101344
+ var scene = this;
101149
101345
 
101150
- this.camera.mouseListener.enabled = false;
101151
- this.container.removeEventListener('wheel', this.camera.wheelListener);
101152
- this.camera = this.glplot.camera = null;
101153
- this.glplot.dispose();
101154
- this.container.parentNode.removeChild(this.container);
101155
- this.glplot = null;
101346
+ if(!scene.glplot) return;
101347
+ scene.camera.mouseListener.enabled = false;
101348
+ scene.container.removeEventListener('wheel', scene.camera.wheelListener);
101349
+ scene.camera = null;
101350
+ scene.glplot.dispose();
101351
+ scene.container.parentNode.removeChild(scene.container);
101352
+ scene.glplot = null;
101156
101353
  };
101157
101354
 
101158
101355
  // getCameraArrays :: plotly_coords -> gl-plot3d_coords
@@ -101178,42 +101375,34 @@ function getLayoutCamera(camera) {
101178
101375
 
101179
101376
  // get camera position in plotly coords from 'gl-plot3d' coords
101180
101377
  proto.getCamera = function() {
101181
- this.glplot.camera.view.recalcMatrix(this.camera.view.lastT());
101182
- return getLayoutCamera(this.glplot.camera);
101378
+ var scene = this;
101379
+ scene.camera.view.recalcMatrix(scene.camera.view.lastT());
101380
+ return getLayoutCamera(scene.camera);
101183
101381
  };
101184
101382
 
101185
101383
  // set gl-plot3d camera position and scene aspects with a set of plotly coords
101186
101384
  proto.setViewport = function(sceneLayout) {
101385
+ var scene = this;
101187
101386
  var cameraData = sceneLayout.camera;
101188
101387
 
101189
- this.glplot.camera.lookAt.apply(this, getCameraArrays(cameraData));
101190
- this.glplot.setAspectratio(sceneLayout.aspectratio);
101388
+ scene.camera.lookAt.apply(this, getCameraArrays(cameraData));
101389
+ scene.glplot.setAspectratio(sceneLayout.aspectratio);
101191
101390
 
101192
101391
  var newOrtho = (cameraData.projection.type === 'orthographic');
101193
- var oldOrtho = this.glplot.camera._ortho;
101392
+ var oldOrtho = scene.camera._ortho;
101194
101393
 
101195
101394
  if(newOrtho !== oldOrtho) {
101196
- this.glplot.redraw();
101197
-
101198
- var RGBA = this.glplot.clearColor;
101199
- this.glplot.gl.clearColor(
101200
- RGBA[0], RGBA[1], RGBA[2], RGBA[3]
101201
- );
101202
- this.glplot.gl.clear(
101203
- this.glplot.gl.DEPTH_BUFFER_BIT |
101204
- this.glplot.gl.COLOR_BUFFER_BIT
101205
- );
101206
-
101207
- this.glplot.dispose();
101208
-
101209
- initializeGLPlot(this);
101210
- this.glplot.camera._ortho = newOrtho;
101395
+ scene.glplot.redraw(); // TODO: figure out why we need to redraw here?
101396
+ scene.glplot.clearRGBA();
101397
+ scene.glplot.dispose();
101398
+ scene.initializeGLPlot();
101211
101399
  }
101212
101400
  };
101213
101401
 
101214
101402
  proto.isCameraChanged = function(layout) {
101215
- var cameraData = this.getCamera();
101216
- var cameraNestedProp = Lib.nestedProperty(layout, this.id + '.camera');
101403
+ var scene = this;
101404
+ var cameraData = scene.getCamera();
101405
+ var cameraNestedProp = Lib.nestedProperty(layout, scene.id + '.camera');
101217
101406
  var cameraDataLastSave = cameraNestedProp.get();
101218
101407
 
101219
101408
  function same(x, y, i, j) {
@@ -101246,8 +101435,9 @@ proto.isCameraChanged = function(layout) {
101246
101435
  };
101247
101436
 
101248
101437
  proto.isAspectChanged = function(layout) {
101249
- var aspectData = this.glplot.getAspectratio();
101250
- var aspectNestedProp = Lib.nestedProperty(layout, this.id + '.aspectratio');
101438
+ var scene = this;
101439
+ var aspectData = scene.glplot.getAspectratio();
101440
+ var aspectNestedProp = Lib.nestedProperty(layout, scene.id + '.aspectratio');
101251
101441
  var aspectDataLastSave = aspectNestedProp.get();
101252
101442
 
101253
101443
  return (
@@ -101260,7 +101450,8 @@ proto.isAspectChanged = function(layout) {
101260
101450
 
101261
101451
  // save camera to user layout (i.e. gd.layout)
101262
101452
  proto.saveLayout = function(layout) {
101263
- var fullLayout = this.fullLayout;
101453
+ var scene = this;
101454
+ var fullLayout = scene.fullLayout;
101264
101455
 
101265
101456
  var cameraData;
101266
101457
  var cameraNestedProp;
@@ -101270,42 +101461,42 @@ proto.saveLayout = function(layout) {
101270
101461
  var aspectNestedProp;
101271
101462
  var aspectDataLastSave;
101272
101463
 
101273
- var cameraChanged = this.isCameraChanged(layout);
101274
- var aspectChanged = this.isAspectChanged(layout);
101464
+ var cameraChanged = scene.isCameraChanged(layout);
101465
+ var aspectChanged = scene.isAspectChanged(layout);
101275
101466
 
101276
101467
  var hasChanged = cameraChanged || aspectChanged;
101277
101468
  if(hasChanged) {
101278
101469
  var preGUI = {};
101279
101470
  if(cameraChanged) {
101280
- cameraData = this.getCamera();
101281
- cameraNestedProp = Lib.nestedProperty(layout, this.id + '.camera');
101471
+ cameraData = scene.getCamera();
101472
+ cameraNestedProp = Lib.nestedProperty(layout, scene.id + '.camera');
101282
101473
  cameraDataLastSave = cameraNestedProp.get();
101283
101474
 
101284
- preGUI[this.id + '.camera'] = cameraDataLastSave;
101475
+ preGUI[scene.id + '.camera'] = cameraDataLastSave;
101285
101476
  }
101286
101477
  if(aspectChanged) {
101287
- aspectData = this.glplot.getAspectratio();
101288
- aspectNestedProp = Lib.nestedProperty(layout, this.id + '.aspectratio');
101478
+ aspectData = scene.glplot.getAspectratio();
101479
+ aspectNestedProp = Lib.nestedProperty(layout, scene.id + '.aspectratio');
101289
101480
  aspectDataLastSave = aspectNestedProp.get();
101290
101481
 
101291
- preGUI[this.id + '.aspectratio'] = aspectDataLastSave;
101482
+ preGUI[scene.id + '.aspectratio'] = aspectDataLastSave;
101292
101483
  }
101293
101484
  Registry.call('_storeDirectGUIEdit', layout, fullLayout._preGUI, preGUI);
101294
101485
 
101295
101486
  if(cameraChanged) {
101296
101487
  cameraNestedProp.set(cameraData);
101297
101488
 
101298
- var cameraFullNP = Lib.nestedProperty(fullLayout, this.id + '.camera');
101489
+ var cameraFullNP = Lib.nestedProperty(fullLayout, scene.id + '.camera');
101299
101490
  cameraFullNP.set(cameraData);
101300
101491
  }
101301
101492
 
101302
101493
  if(aspectChanged) {
101303
101494
  aspectNestedProp.set(aspectData);
101304
101495
 
101305
- var aspectFullNP = Lib.nestedProperty(fullLayout, this.id + '.aspectratio');
101496
+ var aspectFullNP = Lib.nestedProperty(fullLayout, scene.id + '.aspectratio');
101306
101497
  aspectFullNP.set(aspectData);
101307
101498
 
101308
- this.glplot.redraw();
101499
+ scene.glplot.redraw();
101309
101500
  }
101310
101501
  }
101311
101502
 
@@ -101313,7 +101504,8 @@ proto.saveLayout = function(layout) {
101313
101504
  };
101314
101505
 
101315
101506
  proto.updateFx = function(dragmode, hovermode) {
101316
- var camera = this.camera;
101507
+ var scene = this;
101508
+ var camera = scene.camera;
101317
101509
  if(camera) {
101318
101510
  // rotate and orbital are synonymous
101319
101511
  if(dragmode === 'orbit') {
@@ -101327,15 +101519,15 @@ proto.updateFx = function(dragmode, hovermode) {
101327
101519
  // The setter for camera.mode animates the transition to z-up,
101328
101520
  // but only if we *don't* explicitly set z-up earlier via the
101329
101521
  // relayout. So push `up` back to layout & fullLayout manually now.
101330
- var gd = this.graphDiv;
101522
+ var gd = scene.graphDiv;
101331
101523
  var fullLayout = gd._fullLayout;
101332
- var fullCamera = this.fullSceneLayout.camera;
101524
+ var fullCamera = scene.fullSceneLayout.camera;
101333
101525
  var x = fullCamera.up.x;
101334
101526
  var y = fullCamera.up.y;
101335
101527
  var z = fullCamera.up.z;
101336
101528
  // only push `up` back to (full)layout if it's going to change
101337
101529
  if(z / Math.sqrt(x * x + y * y + z * z) < 0.999) {
101338
- var attr = this.id + '.camera.up';
101530
+ var attr = scene.id + '.camera.up';
101339
101531
  var zUp = {x: 0, y: 0, z: 1};
101340
101532
  var edits = {};
101341
101533
  edits[attr] = zUp;
@@ -101351,19 +101543,20 @@ proto.updateFx = function(dragmode, hovermode) {
101351
101543
  }
101352
101544
 
101353
101545
  // to put dragmode and hovermode on the same grounds from relayout
101354
- this.fullSceneLayout.hovermode = hovermode;
101546
+ scene.fullSceneLayout.hovermode = hovermode;
101355
101547
  };
101356
101548
 
101357
101549
  proto.toImage = function(format) {
101358
- if(!format) format = 'png';
101550
+ var scene = this;
101359
101551
 
101360
- if(this.staticMode) this.container.appendChild(STATIC_CANVAS);
101552
+ if(!format) format = 'png';
101553
+ if(scene.staticMode) scene.container.appendChild(STATIC_CANVAS);
101361
101554
 
101362
101555
  // Force redraw
101363
- this.glplot.redraw();
101556
+ scene.glplot.redraw();
101364
101557
 
101365
101558
  // Grab context and yank out pixels
101366
- var gl = this.glplot.gl;
101559
+ var gl = scene.glplot.gl;
101367
101560
  var w = gl.drawingBufferWidth;
101368
101561
  var h = gl.drawingBufferHeight;
101369
101562
 
@@ -101404,36 +101597,37 @@ proto.toImage = function(format) {
101404
101597
  dataURL = canvas.toDataURL('image/png');
101405
101598
  }
101406
101599
 
101407
- if(this.staticMode) this.container.removeChild(STATIC_CANVAS);
101600
+ if(scene.staticMode) scene.container.removeChild(STATIC_CANVAS);
101408
101601
 
101409
101602
  return dataURL;
101410
101603
  };
101411
101604
 
101412
101605
  proto.setConvert = function() {
101606
+ var scene = this;
101413
101607
  for(var i = 0; i < 3; i++) {
101414
- var ax = this.fullSceneLayout[axisProperties[i]];
101415
- Axes.setConvert(ax, this.fullLayout);
101608
+ var ax = scene.fullSceneLayout[axisProperties[i]];
101609
+ Axes.setConvert(ax, scene.fullLayout);
101416
101610
  ax.setScale = Lib.noop;
101417
101611
  }
101418
101612
  };
101419
101613
 
101420
101614
  proto.make4thDimension = function() {
101421
- var _this = this;
101422
- var gd = _this.graphDiv;
101615
+ var scene = this;
101616
+ var gd = scene.graphDiv;
101423
101617
  var fullLayout = gd._fullLayout;
101424
101618
 
101425
101619
  // mock axis for hover formatting
101426
- _this.mockAxis = {
101620
+ scene._mockAxis = {
101427
101621
  type: 'linear',
101428
101622
  showexponent: 'all',
101429
101623
  exponentformat: 'B'
101430
101624
  };
101431
- Axes.setConvert(_this.mockAxis, fullLayout);
101625
+ Axes.setConvert(scene._mockAxis, fullLayout);
101432
101626
  };
101433
101627
 
101434
101628
  module.exports = Scene;
101435
101629
 
101436
- },{"../../components/fx":414,"../../lib":496,"../../lib/show_no_webgl_msg":516,"../../lib/str2rgbarray":518,"../../plots/cartesian/axes":542,"../../registry":594,"./layout/convert":575,"./layout/spikes":578,"./layout/tick_marks":579,"./project":580,"gl-plot3d":143,"has-passive-events":252,"webgl-context":357}],582:[function(_dereq_,module,exports){
101630
+ },{"../../components/fx":414,"../../lib":496,"../../lib/show_no_webgl_msg":516,"../../lib/str2rgbarray":518,"../../plots/cartesian/axes":542,"../../registry":594,"./layout/convert":575,"./layout/spikes":578,"./layout/tick_marks":579,"./project":580,"gl-plot3d":143,"has-passive-events":252,"is-mobile":260,"webgl-context":357}],582:[function(_dereq_,module,exports){
101437
101631
  /**
101438
101632
  * Copyright 2012-2020, Plotly, Inc.
101439
101633
  * All rights reserved.
@@ -103107,10 +103301,13 @@ plots.supplyTraceDefaults = function(traceIn, traceOut, colorIndex, layout, trac
103107
103301
  var subplots = layout._subplots;
103108
103302
  var subplotId = '';
103109
103303
 
103110
- // TODO - currently if we draw an empty gl2d subplot, it draws
103111
- // nothing then gets stuck and you can't get it back without newPlot
103112
- // sort this out in the regl refactor? but for now just drop empty gl2d subplots
103113
- if(basePlotModule.name !== 'gl2d' || visible) {
103304
+ if(
103305
+ visible ||
103306
+ basePlotModule.name !== 'gl2d' // for now just drop empty gl2d subplots
103307
+ // TODO - currently if we draw an empty gl2d subplot, it draws
103308
+ // nothing then gets stuck and you can't get it back without newPlot
103309
+ // sort this out in the regl refactor?
103310
+ ) {
103114
103311
  if(Array.isArray(subplotAttr)) {
103115
103312
  for(i = 0; i < subplotAttr.length; i++) {
103116
103313
  var attri = subplotAttr[i];
@@ -104769,7 +104966,7 @@ plots.doCalcdata = function(gd, traces) {
104769
104966
  calcdata[i] = cd;
104770
104967
  }
104771
104968
 
104772
- setupAxisCategories(axList, fullData);
104969
+ setupAxisCategories(axList, fullData, fullLayout);
104773
104970
 
104774
104971
  // 'transform' loop - must calc container traces first
104775
104972
  // so that if their dependent traces can get transform properly
@@ -104777,7 +104974,7 @@ plots.doCalcdata = function(gd, traces) {
104777
104974
  for(i = 0; i < fullData.length; i++) transformCalci(i);
104778
104975
 
104779
104976
  // clear stuff that should recomputed in 'regular' loop
104780
- if(hasCalcTransform) setupAxisCategories(axList, fullData);
104977
+ if(hasCalcTransform) setupAxisCategories(axList, fullData, fullLayout);
104781
104978
 
104782
104979
  // 'regular' loop - make sure container traces (eg carpet) calc before
104783
104980
  // contained traces (eg contourcarpet)
@@ -104982,13 +105179,31 @@ function sortAxisCategoriesByValue(axList, gd) {
104982
105179
  return affectedTraces;
104983
105180
  }
104984
105181
 
104985
- function setupAxisCategories(axList, fullData) {
104986
- for(var i = 0; i < axList.length; i++) {
104987
- var ax = axList[i];
105182
+ function setupAxisCategories(axList, fullData, fullLayout) {
105183
+ var axLookup = {};
105184
+ var i, ax, axId;
105185
+
105186
+ for(i = 0; i < axList.length; i++) {
105187
+ ax = axList[i];
105188
+ axId = ax._id;
105189
+
104988
105190
  ax.clearCalc();
104989
105191
  if(ax.type === 'multicategory') {
104990
105192
  ax.setupMultiCategory(fullData);
104991
105193
  }
105194
+
105195
+ axLookup[ax._id] = 1;
105196
+ }
105197
+
105198
+ // look into match groups for 'missing' axes
105199
+ var matchGroups = fullLayout._axisMatchGroups || [];
105200
+ for(i = 0; i < matchGroups.length; i++) {
105201
+ for(axId in matchGroups[i]) {
105202
+ if(!axLookup[axId]) {
105203
+ ax = fullLayout[axisIDs.id2name(axId)];
105204
+ ax.clearCalc();
105205
+ }
105206
+ }
104992
105207
  }
104993
105208
  }
104994
105209
 
@@ -110696,11 +110911,15 @@ proto.handlePick = function(selection) {
110696
110911
  if(selection.object === this.mesh) {
110697
110912
  var selectIndex = selection.index = selection.data.index;
110698
110913
 
110699
- selection.traceCoordinate = [
110700
- this.data.x[selectIndex],
110701
- this.data.y[selectIndex],
110702
- this.data.z[selectIndex]
110703
- ];
110914
+ if(selection.data._cellCenter) {
110915
+ selection.traceCoordinate = selection.data.dataCoordinate;
110916
+ } else {
110917
+ selection.traceCoordinate = [
110918
+ this.data.x[selectIndex],
110919
+ this.data.y[selectIndex],
110920
+ this.data.z[selectIndex]
110921
+ ];
110922
+ }
110704
110923
 
110705
110924
  var text = this.data.hovertext || this.data.text;
110706
110925
  if(Array.isArray(text) && text[selectIndex] !== undefined) {