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
@@ -30,10 +30,269 @@ var createAxesOptions = require('./layout/convert');
30
30
  var createSpikeOptions = require('./layout/spikes');
31
31
  var computeTickMarks = require('./layout/tick_marks');
32
32
 
33
+ var isMobile = require('is-mobile');
34
+ var tablet = isTablet();
35
+
36
+ function isTablet() {
37
+ if(!navigator) return false;
38
+
39
+ var ua;
40
+ // same interface as applied by is-mobile module
41
+ if(!ua && typeof navigator !== 'undefined') ua = navigator.userAgent;
42
+ if(ua && ua.headers && typeof ua.headers['user-agent'] === 'string') {
43
+ ua = ua.headers['user-agent'];
44
+ }
45
+ if(typeof ua !== 'string') return false;
46
+
47
+ var result = isMobile({
48
+ ua: ua,
49
+ tablet: true
50
+ });
51
+
52
+ // handle iPad pro or iPad with iOs 13 using Safari
53
+ // see https://github.com/plotly/plotly.js/issues/4502
54
+ if(
55
+ result === false &&
56
+ ua.indexOf('Macintosh') !== -1 &&
57
+ ua.indexOf('Safari') !== -1 &&
58
+ navigator.maxTouchPoints > 1
59
+ ) {
60
+ result = true;
61
+ }
62
+
63
+ return result;
64
+ }
65
+
33
66
 
34
67
  var STATIC_CANVAS, STATIC_CONTEXT;
35
68
 
36
- function render(scene) {
69
+ function Scene(options, fullLayout) {
70
+ // create sub container for plot
71
+ var sceneContainer = document.createElement('div');
72
+ var plotContainer = options.container;
73
+
74
+ // keep a ref to the graph div to fire hover+click events
75
+ this.graphDiv = options.graphDiv;
76
+
77
+ // create SVG container for hover text
78
+ var svgContainer = document.createElementNS(
79
+ 'http://www.w3.org/2000/svg',
80
+ 'svg');
81
+ svgContainer.style.position = 'absolute';
82
+ svgContainer.style.top = svgContainer.style.left = '0px';
83
+ svgContainer.style.width = svgContainer.style.height = '100%';
84
+ svgContainer.style['z-index'] = 20;
85
+ svgContainer.style['pointer-events'] = 'none';
86
+ sceneContainer.appendChild(svgContainer);
87
+ this.svgContainer = svgContainer;
88
+
89
+ // Tag the container with the sceneID
90
+ sceneContainer.id = options.id;
91
+ sceneContainer.style.position = 'absolute';
92
+ sceneContainer.style.top = sceneContainer.style.left = '0px';
93
+ sceneContainer.style.width = sceneContainer.style.height = '100%';
94
+ plotContainer.appendChild(sceneContainer);
95
+
96
+ this.fullLayout = fullLayout;
97
+ this.id = options.id || 'scene';
98
+ this.fullSceneLayout = fullLayout[this.id];
99
+
100
+ // Saved from last call to plot()
101
+ this.plotArgs = [ [], {}, {} ];
102
+
103
+ /*
104
+ * Move this to calc step? Why does it work here?
105
+ */
106
+ this.axesOptions = createAxesOptions(fullLayout, fullLayout[this.id]);
107
+ this.spikeOptions = createSpikeOptions(fullLayout[this.id]);
108
+ this.container = sceneContainer;
109
+ this.staticMode = !!options.staticPlot;
110
+ this.pixelRatio = this.pixelRatio || options.plotGlPixelRatio || 2;
111
+
112
+ // Coordinate rescaling
113
+ this.dataScale = [1, 1, 1];
114
+
115
+ this.contourLevels = [ [], [], [] ];
116
+
117
+ this.convertAnnotations = Registry.getComponentMethod('annotations3d', 'convert');
118
+ this.drawAnnotations = Registry.getComponentMethod('annotations3d', 'draw');
119
+
120
+ this.initializeGLPlot();
121
+ }
122
+
123
+ var proto = Scene.prototype;
124
+
125
+ proto.tryCreatePlot = function() {
126
+ var scene = this;
127
+ var opts = {
128
+ canvas: scene.canvas,
129
+ gl: scene.gl,
130
+ glOptions: {
131
+ preserveDrawingBuffer: tablet,
132
+ premultipliedAlpha: true,
133
+ antialias: true
134
+ },
135
+ container: scene.container,
136
+ axes: scene.axesOptions,
137
+ spikes: scene.spikeOptions,
138
+ pickRadius: 10,
139
+ snapToData: true,
140
+ autoScale: true,
141
+ autoBounds: false,
142
+ cameraObject: scene.camera,
143
+ pixelRatio: scene.pixelRatio
144
+ };
145
+
146
+ // for static plots, we reuse the WebGL context
147
+ // as WebKit doesn't collect them reliably
148
+ if(scene.staticMode) {
149
+ if(!STATIC_CONTEXT) {
150
+ STATIC_CANVAS = document.createElement('canvas');
151
+ STATIC_CONTEXT = getContext({
152
+ canvas: STATIC_CANVAS,
153
+ preserveDrawingBuffer: true,
154
+ premultipliedAlpha: true,
155
+ antialias: true
156
+ });
157
+ if(!STATIC_CONTEXT) {
158
+ throw new Error('error creating static canvas/context for image server');
159
+ }
160
+ }
161
+
162
+ opts.gl = STATIC_CONTEXT;
163
+ opts.canvas = STATIC_CANVAS;
164
+ }
165
+
166
+ var failed = 0;
167
+
168
+ try {
169
+ scene.glplot = createPlot(opts);
170
+ } catch(e) {
171
+ failed++;
172
+ try { // try second time to fix issue with Chrome 77 https://github.com/plotly/plotly.js/issues/4233
173
+ scene.glplot = createPlot(opts);
174
+ } catch(e) {
175
+ failed++;
176
+ }
177
+ }
178
+
179
+ return failed < 2;
180
+ };
181
+
182
+ proto.initializeGLCamera = function() {
183
+ var scene = this;
184
+ var cameraData = scene.fullSceneLayout.camera;
185
+ var isOrtho = (cameraData.projection.type === 'orthographic');
186
+
187
+ scene.camera = createCamera(scene.container, {
188
+ center: [cameraData.center.x, cameraData.center.y, cameraData.center.z],
189
+ eye: [cameraData.eye.x, cameraData.eye.y, cameraData.eye.z],
190
+ up: [cameraData.up.x, cameraData.up.y, cameraData.up.z],
191
+ _ortho: isOrtho,
192
+ zoomMin: 0.01,
193
+ zoomMax: 100,
194
+ mode: 'orbit'
195
+ });
196
+ };
197
+
198
+ proto.initializeGLPlot = function() {
199
+ var scene = this;
200
+
201
+ scene.initializeGLCamera();
202
+
203
+ var success = scene.tryCreatePlot();
204
+ /*
205
+ * createPlot will throw when webgl is not enabled in the client.
206
+ * Lets return an instance of the module with all functions noop'd.
207
+ * The destroy method - which will remove the container from the DOM
208
+ * is overridden with a function that removes the container only.
209
+ */
210
+ if(!success) return showNoWebGlMsg(scene);
211
+
212
+ // List of scene objects
213
+ scene.traces = {};
214
+
215
+ scene.make4thDimension();
216
+
217
+ var gd = scene.graphDiv;
218
+ var layout = gd.layout;
219
+
220
+ var makeUpdate = function() {
221
+ var update = {};
222
+
223
+ if(scene.isCameraChanged(layout)) {
224
+ // camera updates
225
+ update[scene.id + '.camera'] = scene.getCamera();
226
+ }
227
+
228
+ if(scene.isAspectChanged(layout)) {
229
+ // scene updates
230
+ update[scene.id + '.aspectratio'] = scene.glplot.getAspectratio();
231
+ }
232
+
233
+ return update;
234
+ };
235
+
236
+ var relayoutCallback = function(scene) {
237
+ if(scene.fullSceneLayout.dragmode === false) return;
238
+
239
+ var update = makeUpdate();
240
+ scene.saveLayout(layout);
241
+ scene.graphDiv.emit('plotly_relayout', update);
242
+ };
243
+
244
+ scene.glplot.canvas.addEventListener('mouseup', function() {
245
+ relayoutCallback(scene);
246
+ });
247
+
248
+ scene.glplot.canvas.addEventListener('wheel', function(e) {
249
+ if(gd._context._scrollZoom.gl3d) {
250
+ if(scene.camera._ortho) {
251
+ var s = (e.deltaX > e.deltaY) ? 1.1 : 1.0 / 1.1;
252
+ var o = scene.glplot.getAspectratio();
253
+ scene.glplot.setAspectratio({
254
+ x: s * o.x,
255
+ y: s * o.y,
256
+ z: s * o.z
257
+ });
258
+ }
259
+
260
+ relayoutCallback(scene);
261
+ }
262
+ }, passiveSupported ? {passive: false} : false);
263
+
264
+ scene.glplot.canvas.addEventListener('mousemove', function() {
265
+ if(scene.fullSceneLayout.dragmode === false) return;
266
+ if(scene.camera.mouseListener.buttons === 0) return;
267
+
268
+ var update = makeUpdate();
269
+ scene.graphDiv.emit('plotly_relayouting', update);
270
+ });
271
+
272
+ if(!scene.staticMode) {
273
+ scene.glplot.canvas.addEventListener('webglcontextlost', function(event) {
274
+ if(gd && gd.emit) {
275
+ gd.emit('plotly_webglcontextlost', {
276
+ event: event,
277
+ layer: scene.id
278
+ });
279
+ }
280
+ }, false);
281
+ }
282
+
283
+ scene.glplot.oncontextloss = function() {
284
+ scene.recoverContext();
285
+ };
286
+
287
+ scene.glplot.onrender = function() {
288
+ scene.render();
289
+ };
290
+
291
+ return true;
292
+ };
293
+
294
+ proto.render = function() {
295
+ var scene = this;
37
296
  var gd = scene.graphDiv;
38
297
  var trace;
39
298
 
@@ -128,7 +387,7 @@ function render(scene) {
128
387
  }
129
388
  tx = vectorTx.join('<br>');
130
389
  } else if(trace.type === 'isosurface' || trace.type === 'volume') {
131
- labels.valueLabel = Axes.tickText(scene.mockAxis, scene.mockAxis.d2l(selection.traceCoordinate[3]), 'hover').text;
390
+ labels.valueLabel = Axes.tickText(scene._mockAxis, scene._mockAxis.d2l(selection.traceCoordinate[3]), 'hover').text;
132
391
  vectorTx.push('value: ' + labels.valueLabel);
133
392
  if(selection.textLabel) {
134
393
  vectorTx.push(selection.textLabel);
@@ -195,242 +454,25 @@ function render(scene) {
195
454
  }
196
455
 
197
456
  scene.drawAnnotations(scene);
198
- }
199
-
200
- function tryCreatePlot(scene, cameraObject, pixelRatio, canvas, gl) {
201
- var glplotOptions = {
202
- canvas: canvas,
203
- gl: gl,
204
- container: scene.container,
205
- axes: scene.axesOptions,
206
- spikes: scene.spikeOptions,
207
- pickRadius: 10,
208
- snapToData: true,
209
- autoScale: true,
210
- autoBounds: false,
211
- cameraObject: cameraObject,
212
- pixelRatio: pixelRatio
213
- };
214
-
215
- // for static plots, we reuse the WebGL context
216
- // as WebKit doesn't collect them reliably
217
- if(scene.staticMode) {
218
- if(!STATIC_CONTEXT) {
219
- STATIC_CANVAS = document.createElement('canvas');
220
- STATIC_CONTEXT = getContext({
221
- canvas: STATIC_CANVAS,
222
- preserveDrawingBuffer: true,
223
- premultipliedAlpha: true,
224
- antialias: true
225
- });
226
- if(!STATIC_CONTEXT) {
227
- throw new Error('error creating static canvas/context for image server');
228
- }
229
- }
230
- glplotOptions.pixelRatio = scene.pixelRatio;
231
- glplotOptions.gl = STATIC_CONTEXT;
232
- glplotOptions.canvas = STATIC_CANVAS;
233
- }
234
-
235
- var failed = 0;
236
-
237
- try {
238
- scene.glplot = createPlot(glplotOptions);
239
- } catch(e) {
240
- failed++;
241
- try { // try second time to fix issue with Chrome 77 https://github.com/plotly/plotly.js/issues/4233
242
- scene.glplot = createPlot(glplotOptions);
243
- } catch(e) {
244
- failed++;
245
- }
246
- }
247
-
248
- return failed < 2;
249
- }
250
-
251
- function initializeGLPlot(scene, canvas, gl) {
252
- scene.initializeGLCamera();
253
-
254
- var success = tryCreatePlot(scene, scene.camera, scene.pixelRatio, canvas, gl);
255
- /*
256
- * createPlot will throw when webgl is not enabled in the client.
257
- * Lets return an instance of the module with all functions noop'd.
258
- * The destroy method - which will remove the container from the DOM
259
- * is overridden with a function that removes the container only.
260
- */
261
- if(!success) return showNoWebGlMsg(scene);
262
-
263
- var gd = scene.graphDiv;
264
- var layout = gd.layout;
265
-
266
- var makeUpdate = function() {
267
- var update = {};
268
-
269
- if(scene.isCameraChanged(layout)) {
270
- // camera updates
271
- update[scene.id + '.camera'] = scene.getCamera();
272
- }
273
-
274
- if(scene.isAspectChanged(layout)) {
275
- // scene updates
276
- update[scene.id + '.aspectratio'] = scene.glplot.getAspectratio();
277
- }
278
-
279
- return update;
280
- };
281
-
282
- var relayoutCallback = function(scene) {
283
- if(scene.fullSceneLayout.dragmode === false) return;
284
-
285
- var update = makeUpdate();
286
- scene.saveLayout(layout);
287
- scene.graphDiv.emit('plotly_relayout', update);
288
- };
289
-
290
- scene.glplot.canvas.addEventListener('mouseup', function() {
291
- relayoutCallback(scene);
292
- });
293
-
294
- scene.glplot.canvas.addEventListener('wheel', function(e) {
295
- if(gd._context._scrollZoom.gl3d) {
296
- if(scene.glplot.camera._ortho) {
297
- var s = (e.deltaX > e.deltaY) ? 1.1 : 1.0 / 1.1;
298
- var o = scene.glplot.getAspectratio();
299
- scene.glplot.setAspectratio({
300
- x: s * o.x,
301
- y: s * o.y,
302
- z: s * o.z
303
- });
304
- }
305
-
306
- relayoutCallback(scene);
307
- }
308
- }, passiveSupported ? {passive: false} : false);
309
-
310
- scene.glplot.canvas.addEventListener('mousemove', function() {
311
- if(scene.fullSceneLayout.dragmode === false) return;
312
- if(scene.camera.mouseListener.buttons === 0) return;
313
-
314
- var update = makeUpdate();
315
- scene.graphDiv.emit('plotly_relayouting', update);
316
- });
317
-
318
- if(!scene.staticMode) {
319
- scene.glplot.canvas.addEventListener('webglcontextlost', function(event) {
320
- if(gd && gd.emit) {
321
- gd.emit('plotly_webglcontextlost', {
322
- event: event,
323
- layer: scene.id
324
- });
325
- }
326
- }, false);
327
- }
328
-
329
- scene.glplot.camera = scene.camera;
330
-
331
- scene.glplot.oncontextloss = function() {
332
- scene.recoverContext();
333
- };
334
-
335
- scene.glplot.onrender = render.bind(null, scene);
336
-
337
- // List of scene objects
338
- scene.traces = {};
339
-
340
- scene.make4thDimension();
341
-
342
- return true;
343
- }
344
-
345
- function Scene(options, fullLayout) {
346
- // create sub container for plot
347
- var sceneContainer = document.createElement('div');
348
- var plotContainer = options.container;
349
-
350
- // keep a ref to the graph div to fire hover+click events
351
- this.graphDiv = options.graphDiv;
352
-
353
- // create SVG container for hover text
354
- var svgContainer = document.createElementNS(
355
- 'http://www.w3.org/2000/svg',
356
- 'svg');
357
- svgContainer.style.position = 'absolute';
358
- svgContainer.style.top = svgContainer.style.left = '0px';
359
- svgContainer.style.width = svgContainer.style.height = '100%';
360
- svgContainer.style['z-index'] = 20;
361
- svgContainer.style['pointer-events'] = 'none';
362
- sceneContainer.appendChild(svgContainer);
363
- this.svgContainer = svgContainer;
364
-
365
- // Tag the container with the sceneID
366
- sceneContainer.id = options.id;
367
- sceneContainer.style.position = 'absolute';
368
- sceneContainer.style.top = sceneContainer.style.left = '0px';
369
- sceneContainer.style.width = sceneContainer.style.height = '100%';
370
- plotContainer.appendChild(sceneContainer);
371
-
372
- this.fullLayout = fullLayout;
373
- this.id = options.id || 'scene';
374
- this.fullSceneLayout = fullLayout[this.id];
375
-
376
- // Saved from last call to plot()
377
- this.plotArgs = [ [], {}, {} ];
378
-
379
- /*
380
- * Move this to calc step? Why does it work here?
381
- */
382
- this.axesOptions = createAxesOptions(fullLayout, fullLayout[this.id]);
383
- this.spikeOptions = createSpikeOptions(fullLayout[this.id]);
384
- this.container = sceneContainer;
385
- this.staticMode = !!options.staticPlot;
386
- this.pixelRatio = this.pixelRatio || options.plotGlPixelRatio || 2;
387
-
388
- // Coordinate rescaling
389
- this.dataScale = [1, 1, 1];
390
-
391
- this.contourLevels = [ [], [], [] ];
392
-
393
- this.convertAnnotations = Registry.getComponentMethod('annotations3d', 'convert');
394
- this.drawAnnotations = Registry.getComponentMethod('annotations3d', 'draw');
395
-
396
- initializeGLPlot(this);
397
- }
398
-
399
- var proto = Scene.prototype;
400
-
401
- proto.initializeGLCamera = function() {
402
- var cameraData = this.fullSceneLayout.camera;
403
- var isOrtho = (cameraData.projection.type === 'orthographic');
404
-
405
- this.camera = createCamera(this.container, {
406
- center: [cameraData.center.x, cameraData.center.y, cameraData.center.z],
407
- eye: [cameraData.eye.x, cameraData.eye.y, cameraData.eye.z],
408
- up: [cameraData.up.x, cameraData.up.y, cameraData.up.z],
409
- _ortho: isOrtho,
410
- zoomMin: 0.01,
411
- zoomMax: 100,
412
- mode: 'orbit'
413
- });
414
457
  };
415
458
 
416
459
  proto.recoverContext = function() {
417
460
  var scene = this;
418
- var gl = this.glplot.gl;
419
- var canvas = this.glplot.canvas;
420
461
 
421
- this.glplot.dispose();
462
+ scene.glplot.dispose();
422
463
 
423
- function tryRecover() {
424
- if(gl.isContextLost()) {
464
+ var tryRecover = function() {
465
+ if(scene.glplot.gl.isContextLost()) {
425
466
  requestAnimationFrame(tryRecover);
426
467
  return;
427
468
  }
428
- if(!initializeGLPlot(scene, canvas, gl)) {
469
+ if(!scene.initializeGLPlot()) {
429
470
  Lib.error('Catastrophic and unrecoverable WebGL error. Context lost.');
430
471
  return;
431
472
  }
432
473
  scene.plot.apply(scene, scene.plotArgs);
433
- }
474
+ };
475
+
434
476
  requestAnimationFrame(tryRecover);
435
477
  };
436
478
 
@@ -498,39 +540,35 @@ function computeAnnotationBounds(scene, bounds) {
498
540
  }
499
541
 
500
542
  proto.plot = function(sceneData, fullLayout, layout) {
543
+ var scene = this;
544
+
501
545
  // Save parameters
502
- this.plotArgs = [sceneData, fullLayout, layout];
546
+ scene.plotArgs = [sceneData, fullLayout, layout];
503
547
 
504
- if(this.glplot.contextLost) return;
548
+ if(scene.glplot.contextLost) return;
505
549
 
506
550
  var data, trace;
507
551
  var i, j, axis, axisType;
508
- var fullSceneLayout = fullLayout[this.id];
509
- var sceneLayout = layout[this.id];
510
-
511
- if(fullSceneLayout.bgcolor) this.glplot.clearColor = str2RGBAarray(fullSceneLayout.bgcolor);
512
- else this.glplot.clearColor = [0, 0, 0, 0];
513
-
514
- this.glplot.snapToData = true;
552
+ var fullSceneLayout = fullLayout[scene.id];
553
+ var sceneLayout = layout[scene.id];
515
554
 
516
555
  // Update layout
517
- this.fullLayout = fullLayout;
518
- this.fullSceneLayout = fullSceneLayout;
556
+ scene.fullLayout = fullLayout;
557
+ scene.fullSceneLayout = fullSceneLayout;
519
558
 
520
- this.glplotLayout = fullSceneLayout;
521
- this.axesOptions.merge(fullLayout, fullSceneLayout);
522
- this.spikeOptions.merge(fullSceneLayout);
559
+ scene.axesOptions.merge(fullLayout, fullSceneLayout);
560
+ scene.spikeOptions.merge(fullSceneLayout);
523
561
 
524
562
  // Update camera and camera mode
525
- this.setViewport(fullSceneLayout);
526
- this.updateFx(fullSceneLayout.dragmode, fullSceneLayout.hovermode);
527
- this.camera.enableWheel = this.graphDiv._context._scrollZoom.gl3d;
563
+ scene.setViewport(fullSceneLayout);
564
+ scene.updateFx(fullSceneLayout.dragmode, fullSceneLayout.hovermode);
565
+ scene.camera.enableWheel = scene.graphDiv._context._scrollZoom.gl3d;
528
566
 
529
- // Update scene
530
- this.glplot.update({});
567
+ // Update scene background
568
+ scene.glplot.setClearColor(str2RGBAarray(fullSceneLayout.bgcolor));
531
569
 
532
570
  // Update axes functions BEFORE updating traces
533
- this.setConvert(axis);
571
+ scene.setConvert(axis);
534
572
 
535
573
  // Convert scene data
536
574
  if(!sceneData) sceneData = [];
@@ -560,10 +598,10 @@ proto.plot = function(sceneData, fullLayout, layout) {
560
598
  }
561
599
 
562
600
  // Save scale
563
- this.dataScale = dataScale;
601
+ scene.dataScale = dataScale;
564
602
 
565
603
  // after computeTraceBounds where ax._categories are filled in
566
- this.convertAnnotations(this);
604
+ scene.convertAnnotations(this);
567
605
 
568
606
  // Update traces
569
607
  for(i = 0; i < sceneData.length; ++i) {
@@ -571,24 +609,24 @@ proto.plot = function(sceneData, fullLayout, layout) {
571
609
  if(data.visible !== true || data._length === 0) {
572
610
  continue;
573
611
  }
574
- trace = this.traces[data.uid];
612
+ trace = scene.traces[data.uid];
575
613
  if(trace) {
576
614
  if(trace.data.type === data.type) {
577
615
  trace.update(data);
578
616
  } else {
579
617
  trace.dispose();
580
618
  trace = data._module.plot(this, data);
581
- this.traces[data.uid] = trace;
619
+ scene.traces[data.uid] = trace;
582
620
  }
583
621
  } else {
584
622
  trace = data._module.plot(this, data);
585
- this.traces[data.uid] = trace;
623
+ scene.traces[data.uid] = trace;
586
624
  }
587
625
  trace.name = data.name;
588
626
  }
589
627
 
590
628
  // Remove empty traces
591
- var traceIds = Object.keys(this.traces);
629
+ var traceIds = Object.keys(scene.traces);
592
630
 
593
631
  traceIdLoop:
594
632
  for(i = 0; i < traceIds.length; ++i) {
@@ -598,13 +636,13 @@ proto.plot = function(sceneData, fullLayout, layout) {
598
636
  continue traceIdLoop;
599
637
  }
600
638
  }
601
- trace = this.traces[traceIds[i]];
639
+ trace = scene.traces[traceIds[i]];
602
640
  trace.dispose();
603
- delete this.traces[traceIds[i]];
641
+ delete scene.traces[traceIds[i]];
604
642
  }
605
643
 
606
644
  // order object per trace index
607
- this.glplot.objects.sort(function(a, b) {
645
+ scene.glplot.objects.sort(function(a, b) {
608
646
  return a._trace.data.index - b._trace.data.index;
609
647
  });
610
648
 
@@ -631,8 +669,8 @@ proto.plot = function(sceneData, fullLayout, layout) {
631
669
  sceneBounds[0][i] = Infinity;
632
670
  sceneBounds[1][i] = -Infinity;
633
671
 
634
- var objects = this.glplot.objects;
635
- var annotations = this.fullSceneLayout.annotations || [];
672
+ var objects = scene.glplot.objects;
673
+ var annotations = scene.fullSceneLayout.annotations || [];
636
674
  var axLetter = axis._name.charAt(0);
637
675
 
638
676
  for(j = 0; j < objects.length; j++) {
@@ -690,8 +728,10 @@ proto.plot = function(sceneData, fullLayout, layout) {
690
728
  axisDataRange[i] = sceneBounds[1][i] - sceneBounds[0][i];
691
729
 
692
730
  // Update plot bounds
693
- this.glplot.bounds[0][i] = sceneBounds[0][i] * dataScale[i];
694
- this.glplot.bounds[1][i] = sceneBounds[1][i] * dataScale[i];
731
+ scene.glplot.setBounds(i, {
732
+ min: sceneBounds[0][i] * dataScale[i],
733
+ max: sceneBounds[1][i] * dataScale[i]
734
+ });
695
735
  }
696
736
 
697
737
  var axesScaleRatio = [1, 1, 1];
@@ -746,11 +786,11 @@ proto.plot = function(sceneData, fullLayout, layout) {
746
786
  * Finally assign the computed aspecratio to the glplot module. This will have an effect
747
787
  * on the next render cycle.
748
788
  */
749
- this.glplot.setAspectratio(fullSceneLayout.aspectratio);
789
+ scene.glplot.setAspectratio(fullSceneLayout.aspectratio);
750
790
 
751
791
  // save 'initial' camera view settings for modebar button
752
- if(!this.viewInitial.aspectratio) {
753
- this.viewInitial.aspectratio = {
792
+ if(!scene.viewInitial.aspectratio) {
793
+ scene.viewInitial.aspectratio = {
754
794
  x: fullSceneLayout.aspectratio.x,
755
795
  y: fullSceneLayout.aspectratio.y,
756
796
  z: fullSceneLayout.aspectratio.z
@@ -762,7 +802,7 @@ proto.plot = function(sceneData, fullLayout, layout) {
762
802
  var size = fullLayout._size || null;
763
803
 
764
804
  if(domain && size) {
765
- var containerStyle = this.container.style;
805
+ var containerStyle = scene.container.style;
766
806
  containerStyle.position = 'absolute';
767
807
  containerStyle.left = (size.l + domain.x[0] * size.w) + 'px';
768
808
  containerStyle.top = (size.t + (1 - domain.y[1]) * size.h) + 'px';
@@ -771,18 +811,19 @@ proto.plot = function(sceneData, fullLayout, layout) {
771
811
  }
772
812
 
773
813
  // force redraw so that promise is returned when rendering is completed
774
- this.glplot.redraw();
814
+ scene.glplot.redraw();
775
815
  };
776
816
 
777
817
  proto.destroy = function() {
778
- if(!this.glplot) return;
779
-
780
- this.camera.mouseListener.enabled = false;
781
- this.container.removeEventListener('wheel', this.camera.wheelListener);
782
- this.camera = this.glplot.camera = null;
783
- this.glplot.dispose();
784
- this.container.parentNode.removeChild(this.container);
785
- this.glplot = null;
818
+ var scene = this;
819
+
820
+ if(!scene.glplot) return;
821
+ scene.camera.mouseListener.enabled = false;
822
+ scene.container.removeEventListener('wheel', scene.camera.wheelListener);
823
+ scene.camera = null;
824
+ scene.glplot.dispose();
825
+ scene.container.parentNode.removeChild(scene.container);
826
+ scene.glplot = null;
786
827
  };
787
828
 
788
829
  // getCameraArrays :: plotly_coords -> gl-plot3d_coords
@@ -808,42 +849,34 @@ function getLayoutCamera(camera) {
808
849
 
809
850
  // get camera position in plotly coords from 'gl-plot3d' coords
810
851
  proto.getCamera = function() {
811
- this.glplot.camera.view.recalcMatrix(this.camera.view.lastT());
812
- return getLayoutCamera(this.glplot.camera);
852
+ var scene = this;
853
+ scene.camera.view.recalcMatrix(scene.camera.view.lastT());
854
+ return getLayoutCamera(scene.camera);
813
855
  };
814
856
 
815
857
  // set gl-plot3d camera position and scene aspects with a set of plotly coords
816
858
  proto.setViewport = function(sceneLayout) {
859
+ var scene = this;
817
860
  var cameraData = sceneLayout.camera;
818
861
 
819
- this.glplot.camera.lookAt.apply(this, getCameraArrays(cameraData));
820
- this.glplot.setAspectratio(sceneLayout.aspectratio);
862
+ scene.camera.lookAt.apply(this, getCameraArrays(cameraData));
863
+ scene.glplot.setAspectratio(sceneLayout.aspectratio);
821
864
 
822
865
  var newOrtho = (cameraData.projection.type === 'orthographic');
823
- var oldOrtho = this.glplot.camera._ortho;
866
+ var oldOrtho = scene.camera._ortho;
824
867
 
825
868
  if(newOrtho !== oldOrtho) {
826
- this.glplot.redraw();
827
-
828
- var RGBA = this.glplot.clearColor;
829
- this.glplot.gl.clearColor(
830
- RGBA[0], RGBA[1], RGBA[2], RGBA[3]
831
- );
832
- this.glplot.gl.clear(
833
- this.glplot.gl.DEPTH_BUFFER_BIT |
834
- this.glplot.gl.COLOR_BUFFER_BIT
835
- );
836
-
837
- this.glplot.dispose();
838
-
839
- initializeGLPlot(this);
840
- this.glplot.camera._ortho = newOrtho;
869
+ scene.glplot.redraw(); // TODO: figure out why we need to redraw here?
870
+ scene.glplot.clearRGBA();
871
+ scene.glplot.dispose();
872
+ scene.initializeGLPlot();
841
873
  }
842
874
  };
843
875
 
844
876
  proto.isCameraChanged = function(layout) {
845
- var cameraData = this.getCamera();
846
- var cameraNestedProp = Lib.nestedProperty(layout, this.id + '.camera');
877
+ var scene = this;
878
+ var cameraData = scene.getCamera();
879
+ var cameraNestedProp = Lib.nestedProperty(layout, scene.id + '.camera');
847
880
  var cameraDataLastSave = cameraNestedProp.get();
848
881
 
849
882
  function same(x, y, i, j) {
@@ -876,8 +909,9 @@ proto.isCameraChanged = function(layout) {
876
909
  };
877
910
 
878
911
  proto.isAspectChanged = function(layout) {
879
- var aspectData = this.glplot.getAspectratio();
880
- var aspectNestedProp = Lib.nestedProperty(layout, this.id + '.aspectratio');
912
+ var scene = this;
913
+ var aspectData = scene.glplot.getAspectratio();
914
+ var aspectNestedProp = Lib.nestedProperty(layout, scene.id + '.aspectratio');
881
915
  var aspectDataLastSave = aspectNestedProp.get();
882
916
 
883
917
  return (
@@ -890,7 +924,8 @@ proto.isAspectChanged = function(layout) {
890
924
 
891
925
  // save camera to user layout (i.e. gd.layout)
892
926
  proto.saveLayout = function(layout) {
893
- var fullLayout = this.fullLayout;
927
+ var scene = this;
928
+ var fullLayout = scene.fullLayout;
894
929
 
895
930
  var cameraData;
896
931
  var cameraNestedProp;
@@ -900,42 +935,42 @@ proto.saveLayout = function(layout) {
900
935
  var aspectNestedProp;
901
936
  var aspectDataLastSave;
902
937
 
903
- var cameraChanged = this.isCameraChanged(layout);
904
- var aspectChanged = this.isAspectChanged(layout);
938
+ var cameraChanged = scene.isCameraChanged(layout);
939
+ var aspectChanged = scene.isAspectChanged(layout);
905
940
 
906
941
  var hasChanged = cameraChanged || aspectChanged;
907
942
  if(hasChanged) {
908
943
  var preGUI = {};
909
944
  if(cameraChanged) {
910
- cameraData = this.getCamera();
911
- cameraNestedProp = Lib.nestedProperty(layout, this.id + '.camera');
945
+ cameraData = scene.getCamera();
946
+ cameraNestedProp = Lib.nestedProperty(layout, scene.id + '.camera');
912
947
  cameraDataLastSave = cameraNestedProp.get();
913
948
 
914
- preGUI[this.id + '.camera'] = cameraDataLastSave;
949
+ preGUI[scene.id + '.camera'] = cameraDataLastSave;
915
950
  }
916
951
  if(aspectChanged) {
917
- aspectData = this.glplot.getAspectratio();
918
- aspectNestedProp = Lib.nestedProperty(layout, this.id + '.aspectratio');
952
+ aspectData = scene.glplot.getAspectratio();
953
+ aspectNestedProp = Lib.nestedProperty(layout, scene.id + '.aspectratio');
919
954
  aspectDataLastSave = aspectNestedProp.get();
920
955
 
921
- preGUI[this.id + '.aspectratio'] = aspectDataLastSave;
956
+ preGUI[scene.id + '.aspectratio'] = aspectDataLastSave;
922
957
  }
923
958
  Registry.call('_storeDirectGUIEdit', layout, fullLayout._preGUI, preGUI);
924
959
 
925
960
  if(cameraChanged) {
926
961
  cameraNestedProp.set(cameraData);
927
962
 
928
- var cameraFullNP = Lib.nestedProperty(fullLayout, this.id + '.camera');
963
+ var cameraFullNP = Lib.nestedProperty(fullLayout, scene.id + '.camera');
929
964
  cameraFullNP.set(cameraData);
930
965
  }
931
966
 
932
967
  if(aspectChanged) {
933
968
  aspectNestedProp.set(aspectData);
934
969
 
935
- var aspectFullNP = Lib.nestedProperty(fullLayout, this.id + '.aspectratio');
970
+ var aspectFullNP = Lib.nestedProperty(fullLayout, scene.id + '.aspectratio');
936
971
  aspectFullNP.set(aspectData);
937
972
 
938
- this.glplot.redraw();
973
+ scene.glplot.redraw();
939
974
  }
940
975
  }
941
976
 
@@ -943,7 +978,8 @@ proto.saveLayout = function(layout) {
943
978
  };
944
979
 
945
980
  proto.updateFx = function(dragmode, hovermode) {
946
- var camera = this.camera;
981
+ var scene = this;
982
+ var camera = scene.camera;
947
983
  if(camera) {
948
984
  // rotate and orbital are synonymous
949
985
  if(dragmode === 'orbit') {
@@ -957,15 +993,15 @@ proto.updateFx = function(dragmode, hovermode) {
957
993
  // The setter for camera.mode animates the transition to z-up,
958
994
  // but only if we *don't* explicitly set z-up earlier via the
959
995
  // relayout. So push `up` back to layout & fullLayout manually now.
960
- var gd = this.graphDiv;
996
+ var gd = scene.graphDiv;
961
997
  var fullLayout = gd._fullLayout;
962
- var fullCamera = this.fullSceneLayout.camera;
998
+ var fullCamera = scene.fullSceneLayout.camera;
963
999
  var x = fullCamera.up.x;
964
1000
  var y = fullCamera.up.y;
965
1001
  var z = fullCamera.up.z;
966
1002
  // only push `up` back to (full)layout if it's going to change
967
1003
  if(z / Math.sqrt(x * x + y * y + z * z) < 0.999) {
968
- var attr = this.id + '.camera.up';
1004
+ var attr = scene.id + '.camera.up';
969
1005
  var zUp = {x: 0, y: 0, z: 1};
970
1006
  var edits = {};
971
1007
  edits[attr] = zUp;
@@ -981,19 +1017,20 @@ proto.updateFx = function(dragmode, hovermode) {
981
1017
  }
982
1018
 
983
1019
  // to put dragmode and hovermode on the same grounds from relayout
984
- this.fullSceneLayout.hovermode = hovermode;
1020
+ scene.fullSceneLayout.hovermode = hovermode;
985
1021
  };
986
1022
 
987
1023
  proto.toImage = function(format) {
988
- if(!format) format = 'png';
1024
+ var scene = this;
989
1025
 
990
- if(this.staticMode) this.container.appendChild(STATIC_CANVAS);
1026
+ if(!format) format = 'png';
1027
+ if(scene.staticMode) scene.container.appendChild(STATIC_CANVAS);
991
1028
 
992
1029
  // Force redraw
993
- this.glplot.redraw();
1030
+ scene.glplot.redraw();
994
1031
 
995
1032
  // Grab context and yank out pixels
996
- var gl = this.glplot.gl;
1033
+ var gl = scene.glplot.gl;
997
1034
  var w = gl.drawingBufferWidth;
998
1035
  var h = gl.drawingBufferHeight;
999
1036
 
@@ -1034,31 +1071,32 @@ proto.toImage = function(format) {
1034
1071
  dataURL = canvas.toDataURL('image/png');
1035
1072
  }
1036
1073
 
1037
- if(this.staticMode) this.container.removeChild(STATIC_CANVAS);
1074
+ if(scene.staticMode) scene.container.removeChild(STATIC_CANVAS);
1038
1075
 
1039
1076
  return dataURL;
1040
1077
  };
1041
1078
 
1042
1079
  proto.setConvert = function() {
1080
+ var scene = this;
1043
1081
  for(var i = 0; i < 3; i++) {
1044
- var ax = this.fullSceneLayout[axisProperties[i]];
1045
- Axes.setConvert(ax, this.fullLayout);
1082
+ var ax = scene.fullSceneLayout[axisProperties[i]];
1083
+ Axes.setConvert(ax, scene.fullLayout);
1046
1084
  ax.setScale = Lib.noop;
1047
1085
  }
1048
1086
  };
1049
1087
 
1050
1088
  proto.make4thDimension = function() {
1051
- var _this = this;
1052
- var gd = _this.graphDiv;
1089
+ var scene = this;
1090
+ var gd = scene.graphDiv;
1053
1091
  var fullLayout = gd._fullLayout;
1054
1092
 
1055
1093
  // mock axis for hover formatting
1056
- _this.mockAxis = {
1094
+ scene._mockAxis = {
1057
1095
  type: 'linear',
1058
1096
  showexponent: 'all',
1059
1097
  exponentformat: 'B'
1060
1098
  };
1061
- Axes.setConvert(_this.mockAxis, fullLayout);
1099
+ Axes.setConvert(scene._mockAxis, fullLayout);
1062
1100
  };
1063
1101
 
1064
1102
  module.exports = Scene;