@@ -10,7 +10,7 @@ import {axisFx, axisFy, axisX, axisY, gridFx, gridFy, gridX, gridY} from "./mark
1010import { frame } from "./marks/frame.js" ;
1111import { tip } from "./marks/tip.js" ;
1212import { 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" ;
1414import { createScales , createScaleFunctions , autoScaleRange , exposeScales } from "./scales.js" ;
1515import { innerDimensions , outerDimensions } from "./scales.js" ;
1616import { position , registry as scaleRegistry } from "./scales/index.js" ;
@@ -48,8 +48,8 @@ export function plot(options = {}) {
4848
4949 // Compute a Map from scale name to an array of associated channels.
5050 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 ) ;
5353
5454 // Add implicit axis marks. Because this happens after faceting (because it
5555 // depends on whether faceting is present), we must initialize the facet state
@@ -139,7 +139,7 @@ export function plot(options = {}) {
139139 }
140140
141141 // Initalize the scales and dimensions.
142- const scaleDescriptors = createScales ( addScaleChannels ( channelsByScale , stateByMark ) , options ) ;
142+ const scaleDescriptors = createScales ( addScaleChannels ( channelsByScale , stateByMark , options ) , options ) ;
143143 const scales = createScaleFunctions ( scaleDescriptors ) ;
144144 const dimensions = createDimensions ( scaleDescriptors , marks , options ) ;
145145
@@ -217,8 +217,8 @@ export function plot(options = {}) {
217217 // reinitialization. Preserve existing scale labels, if any.
218218 if ( newByScale . size ) {
219219 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 ) ) ;
222222 const newScaleDescriptors = inheritScaleLabels ( createScales ( newChannelsByScale , options ) , scaleDescriptors ) ;
223223 const newScales = createScaleFunctions ( newScaleDescriptors ) ;
224224 Object . assign ( scaleDescriptors , newScaleDescriptors ) ;
@@ -410,21 +410,40 @@ function inferChannelScales(channels) {
410410 }
411411}
412412
413- function addScaleChannels ( channelsByScale , stateByMark , filter = yes ) {
413+ function addScaleChannels ( channelsByScale , stateByMark , options , filter = yes ) {
414414 for ( const { channels} of stateByMark . values ( ) ) {
415415 for ( const name in channels ) {
416416 const channel = channels [ name ] ;
417417 const { scale} = channel ;
418418 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+ }
422435 }
423436 }
424437 }
425438 return channelsByScale ;
426439}
427440
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+
428447// Returns the facet groups, and possibly fx and fy channels, associated with
429448// the top-level facet option {data, x, y}.
430449function maybeTopFacet ( facet , options ) {
@@ -518,8 +537,8 @@ function inferAxes(marks, channelsByScale, options) {
518537 } = options ;
519538
520539 // 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 ;
523542 if ( ! channelsByScale . has ( "fx" ) ) fxAxis = fxGrid = null ;
524543 if ( ! channelsByScale . has ( "fy" ) ) fyAxis = fyGrid = null ;
525544
@@ -647,10 +666,11 @@ function hasAxis(marks, k) {
647666 return marks . some ( ( m ) => m . ariaLabel ?. startsWith ( prefix ) ) ;
648667}
649668
650- function hasScaleChannel ( k , marks ) {
669+ function hasPositionChannel ( k , marks ) {
651670 for ( const mark of marks ) {
652671 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" ) {
654674 return true ;
655675 }
656676 }
0 commit comments