diff --git a/apps/climatemappedafrica/src/components/HURUmap/Chart/configureScope.js b/apps/climatemappedafrica/src/components/HURUmap/Chart/configureScope.js index 35efd87ff..e2b25b381 100644 --- a/apps/climatemappedafrica/src/components/HURUmap/Chart/configureScope.js +++ b/apps/climatemappedafrica/src/components/HURUmap/Chart/configureScope.js @@ -1,7 +1,5 @@ import { Scope } from "@hurumap/core"; -import StackedChartScope from "./StackedChartScope"; - import { hurumapArgs } from "@/climatemappedafrica/config"; import theme from "@/climatemappedafrica/theme"; @@ -13,6 +11,7 @@ const { TreemapChartScope, VerticalBarChartScope, VerticalStackedChartScope, + StackedChartScope, } = Scope; export default function configureScope( @@ -66,16 +65,7 @@ export default function configureScope( if (isMobile) { vegaSpec = VerticalStackedChartScope(scopeOptions); } else { - vegaSpec = StackedChartScope( - indicator?.data, - indicator?.metadata, - configuration, - secondaryIndicator?.data ?? null, - showParent ? indicator?.parentData : [{}], - showParent ? secondaryIndicator?.parentData : [{}], - profileNames, - isCompare, - ); + vegaSpec = StackedChartScope(scopeOptions); } break; default: diff --git a/apps/pesayetu/src/components/HURUmap/Chart/StackedChartScope.js b/apps/pesayetu/src/components/HURUmap/Chart/StackedChartScope.js deleted file mode 100644 index 2c4f4e055..000000000 --- a/apps/pesayetu/src/components/HURUmap/Chart/StackedChartScope.js +++ /dev/null @@ -1,411 +0,0 @@ -import merge from "deepmerge"; - -import Scope from "./Scope"; - -import theme from "@/pesayetu/theme"; - -export default function StackedChartScope( - primaryData, - metadata, - config, - secondaryData, - primaryParentData, - secondaryParentData, - profileNames, - isCompare, -) { - const { parentLabel } = config; - - const { primary_group: primaryGroup } = metadata; - const stackedField = config.stacked_field; - - const secondaryLegend = isCompare - ? [ - { - orient: { - value: "none", - }, - legendY: { - signal: "height + 30 ", - }, - labelLimit: 400, - legendX: { signal: "-width/2 - 30" }, - fill: "legend_secondary_scale", - labelFontWeight: "bold", - labelColor: "#666", - labelFont: theme.typography.fontFamily, - }, - ] - : null; - - return merge( - Scope( - primaryData, - metadata, - config, - secondaryData, - primaryParentData, - secondaryParentData, - "stacked", - [ - { - type: "stack", - groupby: [primaryGroup], - field: { signal: "datatype[Units]" }, - }, - ], - ), - { - signals: [ - { - name: "height", - update: "bandspace(domain('yscale').length, 0.1, 0.05) * y_step", - }, - { - name: "stackedField", - value: stackedField, - }, - ], - scales: [ - { - name: "yscale", - type: "band", - domain: { data: "primary_formatted", field: primaryGroup }, - range: { step: { signal: "y_step" } }, - padding: 0.15, - }, - { - name: "xscale", - type: "linear", - domain: { data: "primary_formatted", field: "y1" }, - domainMin: { signal: "domainMin" }, - domainMax: { signal: "domainMax" }, - range: [ - 0, - { - signal: "data('secondary').length > 1 ? width/2 - 30 : width", - }, - ], - zero: true, - clamp: true, - nice: { signal: "primaryXTickCount" }, - }, - { - name: "s_xscale", - type: "linear", - domain: { data: "secondary_formatted", field: "y1" }, - domainMin: { signal: "domainMin" }, - domainMax: { signal: "domainMax" }, - range: [ - 0, - { - signal: "data('secondary').length > 1 ? width/2 - 30 : 0", - }, - ], - zero: true, - clamp: true, - nice: { signal: "secondaryXTickCount" }, - }, - { - name: "color", - type: "ordinal", - range: "category", - domain: { - data: "primary_formatted", - field: stackedField, - sort: true, - }, - }, - { - name: "secondary_color", - type: "ordinal", - range: "secondary", - domain: { - data: "secondary_formatted", - field: stackedField, - }, - }, - { - name: "legend_primary_scale", - type: "ordinal", - domain: [profileNames.primary.toUpperCase()], - range: [theme.palette.primary.main], - }, - { - name: "legend_secondary_scale", - type: "ordinal", - domain: [profileNames.secondary.toUpperCase()], - range: [theme.palette.secondary.main], - }, - { - name: "parent_color_scale", - type: "ordinal", - range: "category", - domain: [parentLabel], - }, - ], - - marks: [ - { - type: "group", - name: "primary_stacked_bars", - encode: { - update: { - x: { value: 0 }, - y: { signal: "chartY" }, - height: { signal: "height" }, - width: { - signal: "data('secondary').length > 1 ? (width / 2 ) : width", - }, - }, - }, - axes: [ - { - orient: "left", - scale: "yscale", - domainOpacity: 0.5, - tickSize: 0, - labelPadding: 6, - zindex: 1, - }, - { - orient: "bottom", - scale: "xscale", - bandPosition: 0, - domainOpacity: 0.5, - tickSize: 0, - format: { signal: "numberFormat[Units]" }, - grid: true, - labelPadding: 6, - tickCount: { signal: "primaryXTickCount" }, - }, - ], - legends: [ - { - fill: "color", - orient: "top", - direction: "horizontal", - strokeColor: "transparent", - labelFont: theme.typography.fontFamily, - encode: { - labels: { - interactive: true, - update: { - fontSize: { value: 11 }, - fill: { value: theme.palette.chart.text.primary }, - }, - }, - symbols: { - update: { - stroke: { value: "transparent" }, - }, - }, - }, - }, - ], - marks: [ - { - name: "bars", - from: { data: "primary_formatted" }, - type: "rect", - encode: { - enter: { - y: { scale: "yscale", field: { signal: "mainGroup" } }, - height: { scale: "yscale", band: 1 }, - x: { scale: "xscale", field: "y0" }, - x2: { scale: "xscale", field: "y1" }, - fill: { scale: "color", field: stackedField }, - }, - update: { - y: { scale: "yscale", field: { signal: "mainGroup" } }, - fillOpacity: { value: 1 }, - x: { scale: "xscale", field: "y0" }, - x2: { scale: "xscale", field: "y1" }, - tooltip: { - signal: - "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value), 'category': datum[stackedField]}", - }, - }, - }, - }, - ], - }, - { - type: "group", - name: "primary_parent_rule", - encode: { - update: { - x: { value: 0 }, - y: { signal: "chartY" }, - height: { signal: "height" }, - }, - }, - legends: - primaryParentData?.length > 1 - ? [ - { - fill: "parent_color_scale", - orient: "none", - legendX: { signal: "width - 90" }, - legendY: { value: -40 }, - labelFont: theme.typography.fontFamily, - labelColor: theme.palette.chart.text.primary, - encode: { - symbols: { - shape: { value: "stroke" }, - update: { - shape: { value: "stroke" }, - size: { value: 500 }, - stroke: { value: theme.palette.chart.text.primary }, - strokeDash: { value: [2, 2] }, - }, - }, - }, - }, - ] - : null, - marks: [ - { - name: "parent", - from: { data: "primary_parent_formatted" }, - type: "rule", - encode: { - update: { - y: { scale: "yscale", field: { signal: "mainGroup" } }, - y2: { - scale: "yscale", - field: { signal: "mainGroup" }, - offset: { signal: "y_step - 5" }, - }, - x: { scale: "xscale", field: "y1" }, - x2: { scale: "xscale", field: "y1" }, - stroke: { - signal: - "datum.primary && (datum[datatype[Units]] > datum.primary[datatype[Units]]) ? grey_mark: white_mark", - }, - strokeWidth: { value: 1 }, - strokeDash: { value: [2, 2] }, - }, - }, - }, - ], - }, - { - type: "group", - name: "secondary_bars", - encode: { - update: { - x: { signal: "(width / 2 ) + 30" }, - y: { signal: "chartY" }, - height: { - signal: "data('secondary').length > 1 ? height : 0", - }, - }, - }, - axes: [ - { - orient: "bottom", - scale: "s_xscale", - bandPosition: 0, - domainOpacity: 0.5, - tickSize: 0, - format: { signal: "numberFormat[Units]" }, - grid: true, - labelPadding: 6, - tickCount: { signal: "secondaryXTickCount" }, - }, - ], - legends: - isCompare && secondaryData?.length > 1 - ? [ - ...secondaryLegend, - { - fill: "secondary_color", - orient: "top", - direction: "horizontal", - strokeColor: "transparent", - labelFont: theme.typography.fontFamily, - encode: { - labels: { - interactive: true, - update: { - fontSize: { value: 11 }, - fill: { value: theme.palette.chart.text.primary }, - }, - }, - symbols: { - update: { - stroke: { value: "transparent" }, - }, - }, - }, - }, - ] - : secondaryLegend, - marks: [ - { - name: "secondary_bars", - from: { data: "secondary_formatted" }, - type: "rect", - encode: { - enter: { - y: { scale: "yscale", field: { signal: "mainGroup" } }, - height: { scale: "yscale", band: 1 }, - x: { scale: "s_xscale", field: "y0" }, - x2: { scale: "s_xscale", field: "y1" }, - fill: { scale: "secondary_color", field: stackedField }, - }, - update: { - fillOpacity: { value: 1 }, - y: { scale: "yscale", field: { signal: "mainGroup" } }, - x: { scale: "s_xscale", field: "y0" }, - tooltip: { - signal: - "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value), 'category': datum[stackedField]}", - }, - }, - }, - }, - ], - }, - { - type: "group", - name: "secondary_parent_rule", - encode: { - update: { - x: { signal: "(width / 2 ) + 30" }, - height: { - signal: "data('secondary').length > 1 ? height : 0", - }, - }, - }, - marks: [ - { - name: "secondary_parent", - from: { data: "secondary_parent_formatted" }, - type: "rule", - encode: { - update: { - y: { scale: "yscale", field: { signal: "mainGroup" } }, - y2: { - scale: "yscale", - field: { signal: "mainGroup" }, - offset: { signal: "y_step - 5" }, - }, - x: { scale: "s_xscale", field: "y1" }, - x2: { scale: "s_xscale", field: "y1" }, - stroke: { - signal: - "datum.secondary && (datum[datatype[Units]] > datum.secondary[datatype[Units]]) ? grey_mark: white_mark", - }, - strokeWidth: { value: 1 }, - strokeDash: { value: [2, 2] }, - }, - }, - }, - ], - }, - ], - }, - ); -} diff --git a/apps/pesayetu/src/components/HURUmap/Chart/configureScope.js b/apps/pesayetu/src/components/HURUmap/Chart/configureScope.js index cdd9f2436..74a253c01 100644 --- a/apps/pesayetu/src/components/HURUmap/Chart/configureScope.js +++ b/apps/pesayetu/src/components/HURUmap/Chart/configureScope.js @@ -1,7 +1,5 @@ import { Scope } from "@hurumap/core"; -import StackedChartScope from "./StackedChartScope"; - import { hurumapArgs } from "@/pesayetu/config"; import theme from "@/pesayetu/theme"; @@ -12,6 +10,7 @@ const { MultiLineChartScope, TreemapChartScope, VerticalBarChartScope, + StackedChartScope, VerticalStackedChartScope, } = Scope; @@ -66,16 +65,7 @@ export default function configureScope( if (isMobile) { vegaSpec = VerticalStackedChartScope(scopeOptions); } else { - vegaSpec = StackedChartScope( - indicator?.data, - indicator?.metadata, - configuration, - secondaryIndicator?.data ?? null, - showParent ? indicator?.parentData : [{}], - showParent ? secondaryIndicator?.parentData : [{}], - profileNames, - isCompare, - ); + vegaSpec = StackedChartScope(scopeOptions); } break; default: diff --git a/apps/climatemappedafrica/src/components/HURUmap/Chart/StackedChartScope.js b/packages/hurumap-core/src/Scope/StackedChartScope.js similarity index 95% rename from apps/climatemappedafrica/src/components/HURUmap/Chart/StackedChartScope.js rename to packages/hurumap-core/src/Scope/StackedChartScope.js index 1d4db49f6..b9758f804 100644 --- a/apps/climatemappedafrica/src/components/HURUmap/Chart/StackedChartScope.js +++ b/packages/hurumap-core/src/Scope/StackedChartScope.js @@ -2,9 +2,7 @@ import merge from "deepmerge"; import Scope from "./Scope"; -import theme from "@/climatemappedafrica/theme"; - -export default function StackedChartScope( +export default function StackedChartScope({ primaryData, metadata, config, @@ -13,7 +11,10 @@ export default function StackedChartScope( secondaryParentData, profileNames, isCompare, -) { + isMobile, + theme, + args, +}) { const { parentLabel } = config; const { primary_group: primaryGroup } = metadata; @@ -38,23 +39,28 @@ export default function StackedChartScope( ] : null; + const transform = [ + { + type: "stack", + groupby: [primaryGroup], + field: { signal: "datatype[Units]" }, + }, + ]; + return merge( - Scope( + Scope({ primaryData, metadata, config, secondaryData, primaryParentData, secondaryParentData, - "stacked", - [ - { - type: "stack", - groupby: [primaryGroup], - field: { signal: "datatype[Units]" }, - }, - ], - ), + chartType: "stacked", + transform, + isMobile, + theme, + args, + }), { signals: [ { @@ -88,6 +94,7 @@ export default function StackedChartScope( ], zero: true, clamp: true, + // TODO: explore why adding nice breaks the chart with error: Error: Cycle detected in dataflow graph. // nice: { signal: "primaryXTickCount" }, }, { @@ -104,6 +111,7 @@ export default function StackedChartScope( ], zero: true, clamp: true, + // TODO: explore why adding nice breaks the chart with error: Error: Cycle detected in dataflow graph. // nice: { signal: "secondaryXTickCount" }, }, { diff --git a/packages/hurumap-core/src/Scope/index.js b/packages/hurumap-core/src/Scope/index.js index 442a5d0ff..6f2b4ed8f 100644 --- a/packages/hurumap-core/src/Scope/index.js +++ b/packages/hurumap-core/src/Scope/index.js @@ -3,6 +3,7 @@ import DonutChartScope from "./DonutChartScope"; import LineChartScope from "./LineChartScope"; import MultiLineChartScope from "./MultiLineChartScope"; import Scope from "./Scope"; +import StackedChartScope from "./StackedChartScope"; import TreemapChartScope from "./TreemapChartScope"; import VerticalBarChartScope from "./VerticalBarChartScope"; import VerticalStackedChartScope from "./VerticalStackedChartScope"; @@ -16,4 +17,5 @@ export default { VerticalBarChartScope, VerticalStackedChartScope, TreemapChartScope, + StackedChartScope, };