@@ -52,17 +52,59 @@ export function plot(options = {}) {
52
52
}
53
53
54
54
const scaleDescriptors = Scales ( scaleChannels , options ) ;
55
- const scales = ScaleFunctions ( scaleDescriptors ) ;
56
55
const axes = Axes ( scaleDescriptors , options ) ;
57
56
const dimensions = Dimensions ( scaleDescriptors , axes , options ) ;
58
57
59
58
autoScaleRange ( scaleDescriptors , dimensions ) ;
60
59
autoScaleLabels ( scaleChannels , scaleDescriptors , axes , dimensions , options ) ;
61
60
autoAxisTicks ( scaleDescriptors , axes ) ;
62
61
62
+ // layouts might return new data to scale with existing or new scales
63
+ const scales = ScaleFunctions ( scaleDescriptors ) ;
64
+ const markValues = new Map ( ) ;
65
+ const newChannels = new Map ( ) ;
66
+ const newOptions = { } ;
67
+ for ( const mark of marks ) {
68
+ const channels = markChannels . get ( mark ) ?? [ ] ;
69
+ const values = applyScales ( channels , scales ) ;
70
+ let index = filter ( markIndex . get ( mark ) , channels , values ) ;
71
+ const rescale = [ ] ;
72
+ if ( mark . layout != null ) {
73
+ let { reindex, ...newValues } = mark . layout ( index , scales , values , dimensions ) || { } ;
74
+ for ( let key in newValues ) {
75
+ let c = newValues [ key ] ;
76
+ const { scale} = c ;
77
+ if ( scale ) {
78
+ if ( ! newChannels . has ( scale ) ) newChannels . set ( scale , [ ] ) ;
79
+ newChannels . get ( scale ) . push ( { scale, value : c . values } ) ;
80
+ newOptions [ scale ] = { ...c . options , ...options [ scale ] } ;
81
+ values [ key ] = c . values ;
82
+ rescale . push ( [ scale , values [ key ] ] ) ;
83
+ } else {
84
+ values [ key ] = c ;
85
+ }
86
+ if ( reindex ) {
87
+ index = range ( values [ key ] ) ;
88
+ reindex = false ;
89
+ }
90
+ }
91
+ }
92
+ markValues . set ( mark , { index, values, rescale} ) ;
93
+ }
94
+ const newScaleDescriptors = Scales ( newChannels , newOptions ) ;
95
+ Object . assign ( scaleDescriptors , newScaleDescriptors ) ;
96
+ Object . assign ( scales , ScaleFunctions ( newScaleDescriptors ) ) ;
97
+ for ( const [ , { rescale} ] of markValues ) {
98
+ for ( const [ scale , values ] of rescale ) {
99
+ for ( let i = 0 ; i < values . length ; i ++ ) {
100
+ values [ i ] = scales [ scale ] ( values [ i ] ) ;
101
+ }
102
+ }
103
+ }
104
+
63
105
// When faceting, render axes for fx and fy instead of x and y.
64
- const x = facet !== undefined && scales . fx ? "fx" : "x" ;
65
- const y = facet !== undefined && scales . fy ? "fy" : "y" ;
106
+ const x = facet !== undefined && scaleDescriptors . fx ? "fx" : "x" ;
107
+ const y = facet !== undefined && scaleDescriptors . fy ? "fy" : "y" ;
66
108
if ( axes [ x ] ) marks . unshift ( axes [ x ] ) ;
67
109
if ( axes [ y ] ) marks . unshift ( axes [ y ] ) ;
68
110
@@ -94,10 +136,7 @@ export function plot(options = {}) {
94
136
. node ( ) ;
95
137
96
138
for ( const mark of marks ) {
97
- const channels = markChannels . get ( mark ) ?? [ ] ;
98
- let values = applyScales ( channels , scales ) ;
99
- const index = filter ( markIndex . get ( mark ) , channels , values ) ;
100
- if ( mark . layout != null ) values = mark . layout ( index , scales , values , dimensions ) ;
139
+ const { index, values} = markValues . get ( mark ) || { } ;
101
140
const node = mark . render ( index , scales , values , dimensions , axes ) ;
102
141
if ( node != null ) svg . appendChild ( node ) ;
103
142
}
@@ -220,6 +259,7 @@ class Facet extends Mark {
220
259
// The following fields are set by initialize:
221
260
this . marksChannels = undefined ; // array of mark channels
222
261
this . marksIndexByFacet = undefined ; // map from facet key to array of mark indexes
262
+ this . marksLayouts = undefined ;
223
263
}
224
264
initialize ( ) {
225
265
const { index, channels} = super . initialize ( ) ;
@@ -229,6 +269,7 @@ class Facet extends Mark {
229
269
const subchannels = [ ] ;
230
270
const marksChannels = this . marksChannels = [ ] ;
231
271
const marksIndexByFacet = this . marksIndexByFacet = facetMap ( channels ) ;
272
+ const marksLayouts = this . marksLayouts = [ ] ;
232
273
for ( const facetKey of facetsKeys ) {
233
274
marksIndexByFacet . set ( facetKey , new Array ( this . marks . length ) ) ;
234
275
}
@@ -260,18 +301,73 @@ class Facet extends Mark {
260
301
subchannels . push ( [ , channel ] ) ;
261
302
}
262
303
marksChannels . push ( markChannels ) ;
304
+ if ( mark . layout ) marksLayouts . push ( mark ) ;
263
305
}
306
+ this . layout = function ( index , scales , channels , dimensions ) {
307
+ const { fx, fy} = scales ;
308
+ const fyMargins = fy && { marginTop : 0 , marginBottom : 0 , height : fy . bandwidth ( ) } ;
309
+ const fxMargins = fx && { marginRight : 0 , marginLeft : 0 , width : fx . bandwidth ( ) } ;
310
+ const subdimensions = { ...dimensions , ...fxMargins , ...fyMargins } ;
311
+
312
+ this . marksValues = marksChannels . map ( channels => applyScales ( channels , scales ) ) ;
313
+ const rescaleChannels = [ ] ;
314
+ for ( let i = 0 ; i < this . marks . length ; ++ i ) {
315
+ const mark = this . marks [ i ] ;
316
+ if ( ! mark . layout ) continue ;
317
+ let values = facetsKeys . map ( facet => [
318
+ facet ,
319
+ mark . layout (
320
+ filter ( marksIndexByFacet . get ( facet ) [ i ] , marksChannels [ i ] , this . marksValues [ i ] ) ,
321
+ scales ,
322
+ this . marksValues [ i ] ,
323
+ subdimensions
324
+ )
325
+ ] ) ;
326
+ if ( values . some ( ( [ , d ] ) => d . reindex ) ) {
327
+ const index = [ ] ;
328
+ const newValues = new Map ( ) ;
329
+ for ( const [ facet , value ] of values ) {
330
+ const j = index . length ;
331
+ const newIndex = new Set ( ) ;
332
+ for ( let key in value ) {
333
+ if ( key === "reindex" ) continue ; // TODO: better internal API
334
+ if ( ! newValues . has ( key ) ) newValues . set ( key , [ ] ) ;
335
+ const V = newValues . get ( key ) ;
336
+ const { scale, options} = value [ key ] ;
337
+ if ( scale ) Object . assign ( V , { scale, options} ) ;
338
+ const U = scale !== undefined ? value [ key ] . values : value [ key ] ;
339
+ for ( let i = 0 ; i < U . length ; i ++ ) {
340
+ const k = i + j ;
341
+ newIndex . add ( k ) ;
342
+ V [ k ] = U [ i ] ;
343
+ }
344
+ }
345
+ for ( const i of newIndex ) index . push ( i ) ;
346
+ marksIndexByFacet . get ( facet ) [ i ] = [ ...newIndex ] ;
347
+ }
348
+ values = Object . fromEntries ( newValues ) ;
349
+ } else {
350
+ values = values [ 0 ] [ 1 ] ;
351
+ }
352
+ this . marksValues [ i ] = values ;
353
+ for ( let k in values ) {
354
+ if ( values [ k ] . scale !== undefined ) {
355
+ rescaleChannels . push ( [ rescaleChannels . length , { values : values [ k ] , scale : values [ k ] . scale , options : values [ k ] . options } ] ) ;
356
+ }
357
+ }
358
+ }
359
+ return Object . fromEntries ( rescaleChannels ) ;
360
+ } ;
264
361
return { index, channels : [ ...channels , ...subchannels ] } ;
265
362
}
266
363
render ( I , scales , channels , dimensions , axes ) {
267
- const { marks, marksChannels, marksIndexByFacet} = this ;
364
+ const { marks, marksChannels, marksValues , marksIndexByFacet} = this ;
268
365
const { fx, fy} = scales ;
269
366
const fyDomain = fy && fy . domain ( ) ;
270
367
const fxDomain = fx && fx . domain ( ) ;
271
368
const fyMargins = fy && { marginTop : 0 , marginBottom : 0 , height : fy . bandwidth ( ) } ;
272
369
const fxMargins = fx && { marginRight : 0 , marginLeft : 0 , width : fx . bandwidth ( ) } ;
273
370
const subdimensions = { ...dimensions , ...fxMargins , ...fyMargins } ;
274
- const marksValues = marksChannels . map ( channels => applyScales ( channels , scales ) ) ;
275
371
return create ( "svg:g" )
276
372
. call ( g => {
277
373
if ( fy && axes . y ) {
@@ -316,7 +412,6 @@ class Facet extends Mark {
316
412
const mark = marks [ i ] ;
317
413
let values = marksValues [ i ] ;
318
414
const index = filter ( marksFacetIndex [ i ] , marksChannels [ i ] , values ) ;
319
- if ( mark . layout != null ) values = mark . layout ( index , scales , values , subdimensions ) ;
320
415
const node = mark . render ( index , scales , values , subdimensions ) ;
321
416
if ( node != null ) this . appendChild ( node ) ;
322
417
}
0 commit comments