@@ -10,7 +10,7 @@ import {axisFx, axisFy, axisX, axisY, gridFx, gridFy, gridX, gridY} from "./mark
10
10
import { frame } from "./marks/frame.js" ;
11
11
import { tip } from "./marks/tip.js" ;
12
12
import { arrayify , isColor , isIterable , isNone , isScaleOptions , map , yes , maybeIntervalTransform } from "./options.js" ;
13
- import { createProjection } from "./projection.js" ;
13
+ import { createProjection , getGeometryChannels , hasProjection } from "./projection.js" ;
14
14
import { createScales , createScaleFunctions , autoScaleRange , exposeScales } from "./scales.js" ;
15
15
import { innerDimensions , outerDimensions } from "./scales.js" ;
16
16
import { position , registry as scaleRegistry } from "./scales/index.js" ;
@@ -48,8 +48,8 @@ export function plot(options = {}) {
48
48
49
49
// Compute a Map from scale name to an array of associated channels.
50
50
const channelsByScale = new Map ( ) ;
51
- if ( topFacetState ) addScaleChannels ( channelsByScale , [ topFacetState ] ) ;
52
- addScaleChannels ( channelsByScale , facetStateByMark ) ;
51
+ if ( topFacetState ) addScaleChannels ( channelsByScale , [ topFacetState ] , options ) ;
52
+ addScaleChannels ( channelsByScale , facetStateByMark , options ) ;
53
53
54
54
// Add implicit axis marks. Because this happens after faceting (because it
55
55
// depends on whether faceting is present), we must initialize the facet state
@@ -139,7 +139,7 @@ export function plot(options = {}) {
139
139
}
140
140
141
141
// Initalize the scales and dimensions.
142
- const scaleDescriptors = createScales ( addScaleChannels ( channelsByScale , stateByMark ) , options ) ;
142
+ const scaleDescriptors = createScales ( addScaleChannels ( channelsByScale , stateByMark , options ) , options ) ;
143
143
const scales = createScaleFunctions ( scaleDescriptors ) ;
144
144
const dimensions = createDimensions ( scaleDescriptors , marks , options ) ;
145
145
@@ -217,8 +217,8 @@ export function plot(options = {}) {
217
217
// reinitialization. Preserve existing scale labels, if any.
218
218
if ( newByScale . size ) {
219
219
const newChannelsByScale = new Map ( ) ;
220
- addScaleChannels ( newChannelsByScale , stateByMark , ( key ) => newByScale . has ( key ) ) ;
221
- addScaleChannels ( channelsByScale , stateByMark , ( key ) => newByScale . has ( key ) ) ;
220
+ addScaleChannels ( newChannelsByScale , stateByMark , options , ( key ) => newByScale . has ( key ) ) ;
221
+ addScaleChannels ( channelsByScale , stateByMark , options , ( key ) => newByScale . has ( key ) ) ;
222
222
const newScaleDescriptors = inheritScaleLabels ( createScales ( newChannelsByScale , options ) , scaleDescriptors ) ;
223
223
const newScales = createScaleFunctions ( newScaleDescriptors ) ;
224
224
Object . assign ( scaleDescriptors , newScaleDescriptors ) ;
@@ -410,21 +410,40 @@ function inferChannelScales(channels) {
410
410
}
411
411
}
412
412
413
- function addScaleChannels ( channelsByScale , stateByMark , filter = yes ) {
413
+ function addScaleChannels ( channelsByScale , stateByMark , options , filter = yes ) {
414
414
for ( const { channels} of stateByMark . values ( ) ) {
415
415
for ( const name in channels ) {
416
416
const channel = channels [ name ] ;
417
417
const { scale} = channel ;
418
418
if ( scale != null && filter ( scale ) ) {
419
- const scaleChannels = channelsByScale . get ( scale ) ;
420
- if ( scaleChannels !== undefined ) scaleChannels . push ( channel ) ;
421
- else channelsByScale . set ( scale , [ channel ] ) ;
419
+ // Geo marks affect the default x and y domains if there is no
420
+ // projection. Skip this (as an optimization) when a projection is
421
+ // specified, or when the domains for x and y are specified.
422
+ if ( scale === "projection" ) {
423
+ if ( ! hasProjection ( options ) ) {
424
+ const gx = options . x ?. domain === undefined ;
425
+ const gy = options . y ?. domain === undefined ;
426
+ if ( gx || gy ) {
427
+ const [ x , y ] = getGeometryChannels ( channel ) ;
428
+ if ( gx ) addScaleChannel ( channelsByScale , "x" , x ) ;
429
+ if ( gy ) addScaleChannel ( channelsByScale , "y" , y ) ;
430
+ }
431
+ }
432
+ } else {
433
+ addScaleChannel ( channelsByScale , scale , channel ) ;
434
+ }
422
435
}
423
436
}
424
437
}
425
438
return channelsByScale ;
426
439
}
427
440
441
+ function addScaleChannel ( channelsByScale , scale , channel ) {
442
+ const scaleChannels = channelsByScale . get ( scale ) ;
443
+ if ( scaleChannels !== undefined ) scaleChannels . push ( channel ) ;
444
+ else channelsByScale . set ( scale , [ channel ] ) ;
445
+ }
446
+
428
447
// Returns the facet groups, and possibly fx and fy channels, associated with
429
448
// the top-level facet option {data, x, y}.
430
449
function maybeTopFacet ( facet , options ) {
@@ -518,8 +537,8 @@ function inferAxes(marks, channelsByScale, options) {
518
537
} = options ;
519
538
520
539
// Disable axes if the corresponding scale is not present.
521
- if ( projection || ( ! isScaleOptions ( x ) && ! hasScaleChannel ( "x" , marks ) ) ) xAxis = xGrid = null ;
522
- if ( projection || ( ! isScaleOptions ( y ) && ! hasScaleChannel ( "y" , marks ) ) ) yAxis = yGrid = null ;
540
+ if ( projection || ( ! isScaleOptions ( x ) && ! hasPositionChannel ( "x" , marks ) ) ) xAxis = xGrid = null ;
541
+ if ( projection || ( ! isScaleOptions ( y ) && ! hasPositionChannel ( "y" , marks ) ) ) yAxis = yGrid = null ;
523
542
if ( ! channelsByScale . has ( "fx" ) ) fxAxis = fxGrid = null ;
524
543
if ( ! channelsByScale . has ( "fy" ) ) fyAxis = fyGrid = null ;
525
544
@@ -647,10 +666,11 @@ function hasAxis(marks, k) {
647
666
return marks . some ( ( m ) => m . ariaLabel ?. startsWith ( prefix ) ) ;
648
667
}
649
668
650
- function hasScaleChannel ( k , marks ) {
669
+ function hasPositionChannel ( k , marks ) {
651
670
for ( const mark of marks ) {
652
671
for ( const key in mark . channels ) {
653
- if ( mark . channels [ key ] . scale === k ) {
672
+ const { scale} = mark . channels [ key ] ;
673
+ if ( scale === k || scale === "projection" ) {
654
674
return true ;
655
675
}
656
676
}
0 commit comments