@@ -17,7 +17,7 @@ export type YDomain = BaseDomain & {
1717export type YBasicSeriesSpec = Pick <
1818 BasicSeriesSpec ,
1919 'id' | 'seriesType' | 'yScaleType' | 'groupId' | 'stackAccessors' | 'yScaleToDataExtent' | 'colorAccessors'
20- > ;
20+ > & { stackAsPercentage ?: boolean } ;
2121
2222export function mergeYDomain (
2323 dataSeries : Map < SpecId , RawDataSeries [ ] > ,
@@ -32,50 +32,54 @@ export function mergeYDomain(
3232 const yDomains = specsByGroupIdsEntries . map (
3333 ( [ groupId , groupSpecs ] ) : YDomain => {
3434 const groupYScaleType = coerceYScaleTypes ( [ ...groupSpecs . stacked , ...groupSpecs . nonStacked ] ) ;
35-
36- // compute stacked domain
37- const isStackedScaleToExtent = groupSpecs . stacked . some ( ( spec ) => {
38- return spec . yScaleToDataExtent ;
39- } ) ;
40- const stackedDataSeries = getDataSeriesOnGroup ( dataSeries , groupSpecs . stacked ) ;
41- const stackedDomain = computeYStackedDomain ( stackedDataSeries , isStackedScaleToExtent ) ;
42-
43- // compute non stacked domain
44- const isNonStackedScaleToExtent = groupSpecs . nonStacked . some ( ( spec ) => {
45- return spec . yScaleToDataExtent ;
46- } ) ;
47- const nonStackedDataSeries = getDataSeriesOnGroup ( dataSeries , groupSpecs . nonStacked ) ;
48- const nonStackedDomain = computeYNonStackedDomain ( nonStackedDataSeries , isNonStackedScaleToExtent ) ;
49-
50- // merge stacked and non stacked domain together
51- const groupDomain = computeContinuousDataDomain (
52- [ ...stackedDomain , ...nonStackedDomain ] ,
53- identity ,
54- isStackedScaleToExtent || isNonStackedScaleToExtent ,
55- ) ;
56-
57- const [ computedDomainMin , computedDomainMax ] = groupDomain ;
58- let domain = groupDomain ;
59-
60- const customDomain = domainsByGroupId . get ( groupId ) ;
61-
62- if ( customDomain && isCompleteBound ( customDomain ) ) {
63- // Don't need to check min > max because this has been validated on axis domain merge
64- domain = [ customDomain . min , customDomain . max ] ;
65- } else if ( customDomain && isLowerBound ( customDomain ) ) {
66- if ( customDomain . min > computedDomainMax ) {
67- throw new Error ( `custom yDomain for ${ groupId } is invalid, custom min is greater than computed max` ) ;
68- }
69-
70- domain = [ customDomain . min , computedDomainMax ] ;
71- } else if ( customDomain && isUpperBound ( customDomain ) ) {
72- if ( computedDomainMin > customDomain . max ) {
73- throw new Error ( `custom yDomain for ${ groupId } is invalid, computed min is greater than custom max` ) ;
35+ const { isPercentageStack } = groupSpecs ;
36+
37+ let domain : number [ ] ;
38+ if ( isPercentageStack ) {
39+ domain = computeContinuousDataDomain ( [ 0 , 1 ] , identity ) ;
40+ } else {
41+ // compute stacked domain
42+ const isStackedScaleToExtent = groupSpecs . stacked . some ( ( spec ) => {
43+ return spec . yScaleToDataExtent ;
44+ } ) ;
45+ const stackedDataSeries = getDataSeriesOnGroup ( dataSeries , groupSpecs . stacked ) ;
46+ const stackedDomain = computeYStackedDomain ( stackedDataSeries , isStackedScaleToExtent ) ;
47+
48+ // compute non stacked domain
49+ const isNonStackedScaleToExtent = groupSpecs . nonStacked . some ( ( spec ) => {
50+ return spec . yScaleToDataExtent ;
51+ } ) ;
52+ const nonStackedDataSeries = getDataSeriesOnGroup ( dataSeries , groupSpecs . nonStacked ) ;
53+ const nonStackedDomain = computeYNonStackedDomain ( nonStackedDataSeries , isNonStackedScaleToExtent ) ;
54+
55+ // merge stacked and non stacked domain together
56+ domain = computeContinuousDataDomain (
57+ [ ...stackedDomain , ...nonStackedDomain ] ,
58+ identity ,
59+ isStackedScaleToExtent || isNonStackedScaleToExtent ,
60+ ) ;
61+
62+ const [ computedDomainMin , computedDomainMax ] = domain ;
63+
64+ const customDomain = domainsByGroupId . get ( groupId ) ;
65+
66+ if ( customDomain && isCompleteBound ( customDomain ) ) {
67+ // Don't need to check min > max because this has been validated on axis domain merge
68+ domain = [ customDomain . min , customDomain . max ] ;
69+ } else if ( customDomain && isLowerBound ( customDomain ) ) {
70+ if ( customDomain . min > computedDomainMax ) {
71+ throw new Error ( `custom yDomain for ${ groupId } is invalid, custom min is greater than computed max` ) ;
72+ }
73+
74+ domain = [ customDomain . min , computedDomainMax ] ;
75+ } else if ( customDomain && isUpperBound ( customDomain ) ) {
76+ if ( computedDomainMin > customDomain . max ) {
77+ throw new Error ( `custom yDomain for ${ groupId } is invalid, computed min is greater than custom max` ) ;
78+ }
79+
80+ domain = [ computedDomainMin , customDomain . max ] ;
7481 }
75-
76- domain = [ computedDomainMin , customDomain . max ] ;
7782 }
78-
7983 return {
8084 type : 'yDomain' ,
8185 isBandScale : false ,
@@ -139,10 +143,14 @@ function computeYNonStackedDomain(dataseries: RawDataSeries[], scaleToExtent: bo
139143 return computeContinuousDataDomain ( [ ...yValues . values ( ) ] , identity , scaleToExtent ) ;
140144}
141145export function splitSpecsByGroupId ( specs : YBasicSeriesSpec [ ] ) {
142- const specsByGroupIds = new Map < GroupId , { stacked : YBasicSeriesSpec [ ] ; nonStacked : YBasicSeriesSpec [ ] } > ( ) ;
146+ const specsByGroupIds = new Map <
147+ GroupId ,
148+ { isPercentageStack : boolean ; stacked : YBasicSeriesSpec [ ] ; nonStacked : YBasicSeriesSpec [ ] }
149+ > ( ) ;
143150 // split each specs by groupId and by stacked or not
144151 specs . forEach ( ( spec ) => {
145152 const group = specsByGroupIds . get ( spec . groupId ) || {
153+ isPercentageStack : false ,
146154 stacked : [ ] ,
147155 nonStacked : [ ] ,
148156 } ;
@@ -151,6 +159,9 @@ export function splitSpecsByGroupId(specs: YBasicSeriesSpec[]) {
151159 } else {
152160 group . nonStacked . push ( spec ) ;
153161 }
162+ if ( spec . stackAsPercentage === true ) {
163+ group . isPercentageStack = true ;
164+ }
154165 specsByGroupIds . set ( spec . groupId , group ) ;
155166 } ) ;
156167 return specsByGroupIds ;
0 commit comments