@@ -13,35 +13,26 @@ var createScatter = require('regl-scatter2d');
13
13
var createLine = require ( 'regl-line2d' ) ;
14
14
var createError = require ( 'regl-error2d' ) ;
15
15
var kdtree = require ( 'kdgrass' ) ;
16
- var rgba = require ( 'color-normalize' ) ;
17
- var svgSdf = require ( 'svg-path-sdf' ) ;
18
16
var arrayRange = require ( 'array-range' ) ;
19
17
20
18
var Registry = require ( '../../registry' ) ;
21
19
var Lib = require ( '../../lib' ) ;
22
20
var AxisIDs = require ( '../../plots/cartesian/axis_ids' ) ;
23
- var Drawing = require ( '../../components/drawing' ) ;
24
- var formatColor = require ( '../../lib/gl_format_color' ) ;
25
21
26
22
var subTypes = require ( '../scatter/subtypes' ) ;
27
23
var calcMarkerSize = require ( '../scatter/calc' ) . calcMarkerSize ;
28
24
var calcAxisExpansion = require ( '../scatter/calc' ) . calcAxisExpansion ;
29
25
var calcColorscales = require ( '../scatter/colorscale_calc' ) ;
30
- var makeBubbleSizeFn = require ( '../scatter/make_bubble_size_func' ) ;
31
26
var linkTraces = require ( '../scatter/link_traces' ) ;
32
27
var getTraceColor = require ( '../scatter/get_trace_color' ) ;
33
28
var fillHoverText = require ( '../scatter/fill_hover_text' ) ;
34
29
35
- var DASHES = require ( '../../constants/gl2d_dashes' ) ;
30
+ var convertStyle = require ( './convert' ) . convertStyle ;
31
+ var convertLinePositions = require ( './convert' ) . convertLinePositions ;
32
+ var convertErrorBarPositions = require ( './convert' ) . convertErrorBarPositions ;
33
+
36
34
var BADNUM = require ( '../../constants/numerical' ) . BADNUM ;
37
- var SYMBOL_SDF_SIZE = 200 ;
38
- var SYMBOL_SIZE = 20 ;
39
- var SYMBOL_STROKE = SYMBOL_SIZE / 20 ;
40
- var SYMBOL_SDF = { } ;
41
- var SYMBOL_SVG_CIRCLE = Drawing . symbolFuncs [ 0 ] ( SYMBOL_SIZE * 0.05 ) ;
42
- var TOO_MANY_POINTS = 1e5 ;
43
- var DOT_RE = / - d o t / ;
44
- var OPEN_RE = / - o p e n / ;
35
+ var TOO_MANY_POINTS = require ( './constants' ) . TOO_MANY_POINTS ;
45
36
46
37
function calc ( gd , trace ) {
47
38
var fullLayout = gd . _fullLayout ;
@@ -91,37 +82,36 @@ function calc(gd, trace) {
91
82
92
83
// create scene options and scene
93
84
calcColorscales ( trace ) ;
94
- var options = sceneOptions ( gd , subplot , trace , positions ) ;
95
- var markerOptions = options . marker ;
85
+ var opts = sceneOptions ( gd , subplot , trace , positions ) ;
96
86
var scene = sceneUpdate ( gd , subplot ) ;
97
- var ppad ;
98
87
99
88
// Re-use SVG scatter axis expansion routine except
100
89
// for graph with very large number of points where it
101
90
// performs poorly.
102
91
// In big data case, fake Axes.expand outputs with data bounds,
103
92
// and an average size for array marker.size inputs.
93
+ var ppad ;
104
94
if ( count < TOO_MANY_POINTS ) {
105
95
ppad = calcMarkerSize ( trace , count ) ;
106
- } else if ( markerOptions ) {
107
- ppad = 2 * ( markerOptions . sizeAvg || Math . max ( markerOptions . size , 3 ) ) ;
96
+ } else if ( opts . marker ) {
97
+ ppad = 2 * ( opts . marker . sizeAvg || Math . max ( opts . marker . size , 3 ) ) ;
108
98
}
109
99
calcAxisExpansion ( gd , trace , xa , ya , x , y , ppad ) ;
110
100
111
101
// set flags to create scene renderers
112
- if ( options . fill && ! scene . fill2d ) scene . fill2d = true ;
113
- if ( options . marker && ! scene . scatter2d ) scene . scatter2d = true ;
114
- if ( options . line && ! scene . line2d ) scene . line2d = true ;
115
- if ( ( options . errorX || options . errorY ) && ! scene . error2d ) scene . error2d = true ;
116
-
117
- // save scene options batch
118
- scene . lineOptions . push ( options . line ) ;
119
- scene . errorXOptions . push ( options . errorX ) ;
120
- scene . errorYOptions . push ( options . errorY ) ;
121
- scene . fillOptions . push ( options . fill ) ;
122
- scene . markerOptions . push ( options . marker ) ;
123
- scene . selectedOptions . push ( options . selected ) ;
124
- scene . unselectedOptions . push ( options . unselected ) ;
102
+ if ( opts . fill && ! scene . fill2d ) scene . fill2d = true ;
103
+ if ( opts . marker && ! scene . scatter2d ) scene . scatter2d = true ;
104
+ if ( opts . line && ! scene . line2d ) scene . line2d = true ;
105
+ if ( ( opts . errorX || opts . errorY ) && ! scene . error2d ) scene . error2d = true ;
106
+
107
+ // save scene opts batch
108
+ scene . lineOptions . push ( opts . line ) ;
109
+ scene . errorXOptions . push ( opts . errorX ) ;
110
+ scene . errorYOptions . push ( opts . errorY ) ;
111
+ scene . fillOptions . push ( opts . fill ) ;
112
+ scene . markerOptions . push ( opts . marker ) ;
113
+ scene . selectedOptions . push ( opts . selected ) ;
114
+ scene . unselectedOptions . push ( opts . unselected ) ;
125
115
scene . count ++ ;
126
116
127
117
// stash scene ref
@@ -138,318 +128,31 @@ function calc(gd, trace) {
138
128
139
129
// create scene options
140
130
function sceneOptions ( gd , subplot , trace , positions ) {
141
- var fullLayout = gd . _fullLayout ;
142
- var count = positions . length / 2 ;
143
- var markerOpts = trace . marker ;
144
- var i ;
145
-
146
- var hasLines , hasErrorX , hasErrorY , hasMarkers , hasFill ;
131
+ var opts = convertStyle ( gd , trace ) ;
147
132
148
- if ( trace . visible !== true ) {
149
- hasLines = false ;
150
- hasErrorX = false ;
151
- hasErrorY = false ;
152
- hasMarkers = false ;
153
- hasFill = false ;
154
- } else {
155
- hasLines = subTypes . hasLines ( trace ) && positions . length > 1 ;
156
- hasErrorX = trace . error_x && trace . error_x . visible === true ;
157
- hasErrorY = trace . error_y && trace . error_y . visible === true ;
158
- hasMarkers = subTypes . hasMarkers ( trace ) ;
159
- hasFill = ! ! trace . fill && trace . fill !== 'none' ;
133
+ if ( opts . marker ) {
134
+ opts . marker . positions = positions ;
160
135
}
161
136
162
- var lineOptions , markerOptions , fillOptions ;
163
- var errorXOptions , errorYOptions ;
164
- var selectedOptions , unselectedOptions ;
165
- var linePositions ;
166
-
167
- if ( hasErrorX || hasErrorY ) {
168
- var calcFromTrace = Registry . getComponentMethod ( 'errorbars' , 'calcFromTrace' ) ;
169
- var errorVals = calcFromTrace ( trace , fullLayout ) ;
170
-
171
- if ( hasErrorX ) {
172
- errorXOptions = makeErrorOptions ( 'x' , trace . error_x , errorVals ) ;
173
- }
174
- if ( hasErrorY ) {
175
- errorYOptions = makeErrorOptions ( 'y' , trace . error_y , errorVals ) ;
176
- }
137
+ if ( opts . line && positions . length > 1 ) {
138
+ Lib . extendFlat (
139
+ opts . line ,
140
+ convertLinePositions ( gd , trace , positions )
141
+ ) ;
177
142
}
178
143
179
- if ( hasLines ) {
180
- lineOptions = { } ;
181
- lineOptions . thickness = trace . line . width ;
182
- lineOptions . color = trace . line . color ;
183
- lineOptions . opacity = trace . opacity ;
184
- lineOptions . overlay = true ;
185
-
186
- var dashes = ( DASHES [ trace . line . dash ] || [ 1 ] ) . slice ( ) ;
187
- for ( i = 0 ; i < dashes . length ; ++ i ) dashes [ i ] *= lineOptions . thickness ;
188
- lineOptions . dashes = dashes ;
189
-
190
- if ( trace . line . shape === 'hv' ) {
191
- linePositions = [ ] ;
192
- for ( i = 0 ; i < Math . floor ( positions . length / 2 ) - 1 ; i ++ ) {
193
- if ( isNaN ( positions [ i * 2 ] ) || isNaN ( positions [ i * 2 + 1 ] ) ) {
194
- linePositions . push ( NaN ) ;
195
- linePositions . push ( NaN ) ;
196
- linePositions . push ( NaN ) ;
197
- linePositions . push ( NaN ) ;
198
- }
199
- else {
200
- linePositions . push ( positions [ i * 2 ] ) ;
201
- linePositions . push ( positions [ i * 2 + 1 ] ) ;
202
- linePositions . push ( positions [ i * 2 + 2 ] ) ;
203
- linePositions . push ( positions [ i * 2 + 1 ] ) ;
204
- }
205
- }
206
- linePositions . push ( positions [ positions . length - 2 ] ) ;
207
- linePositions . push ( positions [ positions . length - 1 ] ) ;
208
- }
209
- else if ( trace . line . shape === 'vh' ) {
210
- linePositions = [ ] ;
211
- for ( i = 0 ; i < Math . floor ( positions . length / 2 ) - 1 ; i ++ ) {
212
- if ( isNaN ( positions [ i * 2 ] ) || isNaN ( positions [ i * 2 + 1 ] ) ) {
213
- linePositions . push ( NaN ) ;
214
- linePositions . push ( NaN ) ;
215
- linePositions . push ( NaN ) ;
216
- linePositions . push ( NaN ) ;
217
- }
218
- else {
219
- linePositions . push ( positions [ i * 2 ] ) ;
220
- linePositions . push ( positions [ i * 2 + 1 ] ) ;
221
- linePositions . push ( positions [ i * 2 ] ) ;
222
- linePositions . push ( positions [ i * 2 + 3 ] ) ;
223
- }
224
- }
225
- linePositions . push ( positions [ positions . length - 2 ] ) ;
226
- linePositions . push ( positions [ positions . length - 1 ] ) ;
227
- }
228
- else {
229
- linePositions = positions ;
230
- }
144
+ if ( opts . errorX || opts . errorY ) {
145
+ var errors = convertErrorBarPositions ( gd , trace , positions ) ;
231
146
232
- // If we have data with gaps, we ought to use rect joins
233
- // FIXME: get rid of this
234
- var hasNaN = false ;
235
- for ( i = 0 ; i < linePositions . length ; i ++ ) {
236
- if ( isNaN ( linePositions [ i ] ) ) {
237
- hasNaN = true ;
238
- break ;
239
- }
147
+ if ( opts . errorX ) {
148
+ Lib . extendFlat ( opts . errorX , errors . x ) ;
240
149
}
241
-
242
- lineOptions . join = ( hasNaN || linePositions . length > TOO_MANY_POINTS ) ? 'rect' :
243
- hasMarkers ? 'rect' : 'round' ;
244
-
245
- // fill gaps
246
- if ( hasNaN && trace . connectgaps ) {
247
- var lastX = linePositions [ 0 ] , lastY = linePositions [ 1 ] ;
248
- for ( i = 0 ; i < linePositions . length ; i += 2 ) {
249
- if ( isNaN ( linePositions [ i ] ) || isNaN ( linePositions [ i + 1 ] ) ) {
250
- linePositions [ i ] = lastX ;
251
- linePositions [ i + 1 ] = lastY ;
252
- }
253
- else {
254
- lastX = linePositions [ i ] ;
255
- lastY = linePositions [ i + 1 ] ;
256
- }
257
- }
150
+ if ( opts . errorY ) {
151
+ Lib . extendFlat ( opts . errorY , errors . y ) ;
258
152
}
259
-
260
- lineOptions . positions = linePositions ;
261
- }
262
-
263
- if ( hasFill ) {
264
- fillOptions = { } ;
265
- fillOptions . fill = trace . fillcolor ;
266
- fillOptions . thickness = 0 ;
267
- fillOptions . closed = true ;
268
153
}
269
154
270
- if ( hasMarkers ) {
271
- markerOptions = makeMarkerOptions ( markerOpts ) ;
272
- selectedOptions = makeSelectedOptions ( trace . selected , markerOpts ) ;
273
- unselectedOptions = makeSelectedOptions ( trace . unselected , markerOpts ) ;
274
- markerOptions . positions = positions ;
275
- }
276
-
277
- function makeErrorOptions ( axLetter , errorOpts , vals ) {
278
- var options = { } ;
279
- options . positions = positions ;
280
-
281
- var ax = AxisIDs . getFromId ( gd , trace [ axLetter + 'axis' ] ) ;
282
- var errors = options . errors = new Float64Array ( 4 * count ) ;
283
- var pOffset = { x : 0 , y : 1 } [ axLetter ] ;
284
- var eOffset = { x : [ 0 , 1 , 2 , 3 ] , y : [ 2 , 3 , 0 , 1 ] } [ axLetter ] ;
285
-
286
- for ( var i = 0 , p = 0 ; i < count ; i ++ , p += 4 ) {
287
- errors [ p + eOffset [ 0 ] ] = positions [ i * 2 + pOffset ] - ax . d2l ( vals [ i ] [ axLetter + 's' ] ) || 0 ;
288
- errors [ p + eOffset [ 1 ] ] = ax . d2l ( vals [ i ] [ axLetter + 'h' ] ) - positions [ i * 2 + pOffset ] || 0 ;
289
- errors [ p + eOffset [ 2 ] ] = 0 ;
290
- errors [ p + eOffset [ 3 ] ] = 0 ;
291
- }
292
-
293
- if ( errorOpts . copy_ystyle ) {
294
- errorOpts = trace . error_y ;
295
- }
296
-
297
- options . capSize = errorOpts . width * 2 ;
298
- options . lineWidth = errorOpts . thickness ;
299
- options . color = errorOpts . color ;
300
-
301
- return options ;
302
- }
303
-
304
- function makeSelectedOptions ( selected , markerOpts ) {
305
- var options = { } ;
306
-
307
- if ( ! selected ) return options ;
308
-
309
- if ( selected . marker && selected . marker . symbol ) {
310
- options = makeMarkerOptions ( Lib . extendFlat ( { } , markerOpts , selected . marker ) ) ;
311
- }
312
-
313
- // shortcut simple selection logic
314
- else {
315
- options = { } ;
316
- if ( selected . marker . size ) options . sizes = selected . marker . size ;
317
- if ( selected . marker . color ) options . colors = selected . marker . color ;
318
- if ( selected . marker . opacity !== undefined ) options . opacity = selected . marker . opacity ;
319
- }
320
-
321
- return options ;
322
- }
323
-
324
- function makeMarkerOptions ( markerOpts ) {
325
- var markerOptions = { } ;
326
- var i ;
327
-
328
- var multiSymbol = Array . isArray ( markerOpts . symbol ) ;
329
- var multiColor = Lib . isArrayOrTypedArray ( markerOpts . color ) ;
330
- var multiLineColor = Lib . isArrayOrTypedArray ( markerOpts . line . color ) ;
331
- var multiOpacity = Lib . isArrayOrTypedArray ( markerOpts . opacity ) ;
332
- var multiSize = Lib . isArrayOrTypedArray ( markerOpts . size ) ;
333
- var multiLineWidth = Lib . isArrayOrTypedArray ( markerOpts . line . width ) ;
334
-
335
- var isOpen ;
336
- if ( ! multiSymbol ) isOpen = OPEN_RE . test ( markerOpts . symbol ) ;
337
-
338
- // prepare colors
339
- if ( multiSymbol || multiColor || multiLineColor || multiOpacity ) {
340
- markerOptions . colors = new Array ( count ) ;
341
- markerOptions . borderColors = new Array ( count ) ;
342
- var colors = formatColor ( markerOpts , markerOpts . opacity , count ) ;
343
- var borderColors = formatColor ( markerOpts . line , markerOpts . opacity , count ) ;
344
-
345
- if ( ! Array . isArray ( borderColors [ 0 ] ) ) {
346
- var borderColor = borderColors ;
347
- borderColors = Array ( count ) ;
348
- for ( i = 0 ; i < count ; i ++ ) {
349
- borderColors [ i ] = borderColor ;
350
- }
351
- }
352
- if ( ! Array . isArray ( colors [ 0 ] ) ) {
353
- var color = colors ;
354
- colors = Array ( count ) ;
355
- for ( i = 0 ; i < count ; i ++ ) {
356
- colors [ i ] = color ;
357
- }
358
- }
359
-
360
- markerOptions . colors = colors ;
361
- markerOptions . borderColors = borderColors ;
362
-
363
- for ( i = 0 ; i < count ; i ++ ) {
364
- if ( multiSymbol ) {
365
- var symbol = markerOpts . symbol [ i ] ;
366
- isOpen = OPEN_RE . test ( symbol ) ;
367
- }
368
- if ( isOpen ) {
369
- borderColors [ i ] = colors [ i ] . slice ( ) ;
370
- colors [ i ] = colors [ i ] . slice ( ) ;
371
- colors [ i ] [ 3 ] = 0 ;
372
- }
373
- }
374
-
375
- markerOptions . opacity = trace . opacity ;
376
- }
377
- else {
378
- if ( isOpen ) {
379
- markerOptions . color = rgba ( markerOpts . color , 'uint8' ) ;
380
- markerOptions . color [ 3 ] = 0 ;
381
- markerOptions . borderColor = rgba ( markerOpts . color , 'uint8' ) ;
382
- } else {
383
- markerOptions . color = rgba ( markerOpts . color , 'uint8' ) ;
384
- markerOptions . borderColor = rgba ( markerOpts . line . color , 'uint8' ) ;
385
- }
386
-
387
- markerOptions . opacity = trace . opacity * markerOpts . opacity ;
388
- }
389
-
390
- // prepare symbols
391
- if ( multiSymbol ) {
392
- markerOptions . markers = new Array ( count ) ;
393
- for ( i = 0 ; i < count ; i ++ ) {
394
- markerOptions . markers [ i ] = getSymbolSdf ( markerOpts . symbol [ i ] ) ;
395
- }
396
- } else {
397
- markerOptions . marker = getSymbolSdf ( markerOpts . symbol ) ;
398
- }
399
-
400
- // prepare sizes
401
- var markerSizeFunc = makeBubbleSizeFn ( trace ) ;
402
- var s ;
403
-
404
- if ( multiSize || multiLineWidth ) {
405
- var sizes = markerOptions . sizes = new Array ( count ) ;
406
- var borderSizes = markerOptions . borderSizes = new Array ( count ) ;
407
- var sizeTotal = 0 ;
408
- var sizeAvg ;
409
-
410
- if ( multiSize ) {
411
- for ( i = 0 ; i < count ; i ++ ) {
412
- sizes [ i ] = markerSizeFunc ( markerOpts . size [ i ] ) ;
413
- sizeTotal += sizes [ i ] ;
414
- }
415
- sizeAvg = sizeTotal / count ;
416
- } else {
417
- s = markerSizeFunc ( markerOpts . size ) ;
418
- for ( i = 0 ; i < count ; i ++ ) {
419
- sizes [ i ] = s ;
420
- }
421
- }
422
-
423
- // See https://github.com/plotly/plotly.js/pull/1781#discussion_r121820798
424
- if ( multiLineWidth ) {
425
- for ( i = 0 ; i < count ; i ++ ) {
426
- borderSizes [ i ] = markerSizeFunc ( markerOpts . line . width [ i ] ) ;
427
- }
428
- } else {
429
- s = markerSizeFunc ( markerOpts . line . width ) ;
430
- for ( i = 0 ; i < count ; i ++ ) {
431
- borderSizes [ i ] = s ;
432
- }
433
- }
434
-
435
- markerOptions . sizeAvg = sizeAvg ;
436
- } else {
437
- markerOptions . size = markerSizeFunc ( markerOpts && markerOpts . size || 10 ) ;
438
- markerOptions . borderSizes = markerSizeFunc ( markerOpts . line . width ) ;
439
- }
440
-
441
- return markerOptions ;
442
- }
443
-
444
- return {
445
- line : lineOptions ,
446
- marker : markerOptions ,
447
- errorX : errorXOptions ,
448
- errorY : errorYOptions ,
449
- fill : fillOptions ,
450
- selected : selectedOptions ,
451
- unselected : unselectedOptions
452
- } ;
155
+ return opts ;
453
156
}
454
157
455
158
// make sure scene exists on subplot, return it
@@ -624,38 +327,6 @@ function sceneUpdate(gd, subplot) {
624
327
return scene ;
625
328
}
626
329
627
- function getSymbolSdf ( symbol ) {
628
- if ( symbol === 'circle' ) return null ;
629
-
630
- var symbolPath , symbolSdf ;
631
- var symbolNumber = Drawing . symbolNumber ( symbol ) ;
632
- var symbolFunc = Drawing . symbolFuncs [ symbolNumber % 100 ] ;
633
- var symbolNoDot = ! ! Drawing . symbolNoDot [ symbolNumber % 100 ] ;
634
- var symbolNoFill = ! ! Drawing . symbolNoFill [ symbolNumber % 100 ] ;
635
-
636
- var isDot = DOT_RE . test ( symbol ) ;
637
-
638
- // get symbol sdf from cache or generate it
639
- if ( SYMBOL_SDF [ symbol ] ) return SYMBOL_SDF [ symbol ] ;
640
-
641
- if ( isDot && ! symbolNoDot ) {
642
- symbolPath = symbolFunc ( SYMBOL_SIZE * 1.1 ) + SYMBOL_SVG_CIRCLE ;
643
- }
644
- else {
645
- symbolPath = symbolFunc ( SYMBOL_SIZE ) ;
646
- }
647
-
648
- symbolSdf = svgSdf ( symbolPath , {
649
- w : SYMBOL_SDF_SIZE ,
650
- h : SYMBOL_SDF_SIZE ,
651
- viewBox : [ - SYMBOL_SIZE , - SYMBOL_SIZE , SYMBOL_SIZE , SYMBOL_SIZE ] ,
652
- stroke : symbolNoFill ? SYMBOL_STROKE : - SYMBOL_STROKE
653
- } ) ;
654
- SYMBOL_SDF [ symbol ] = symbolSdf ;
655
-
656
- return symbolSdf || null ;
657
- }
658
-
659
330
function plot ( gd , subplot , cdata ) {
660
331
if ( ! cdata . length ) return ;
661
332
0 commit comments