diff --git a/app/charts/index.ts b/app/charts/index.ts
index b9370de60..96f0c177a 100644
--- a/app/charts/index.ts
+++ b/app/charts/index.ts
@@ -278,9 +278,10 @@ export const getInitialConfig = ({
componentIri: geoShapes[0]?.iri || "",
measureIri: measures[0].iri,
hierarchyLevel: 1,
+ colorScaleType: "continuous",
+ colorScaleInterpolationType: "linear",
palette: "oranges",
nbClass: 5,
- paletteType: "continuous",
},
symbolLayer: {
show: geoShapes.length === 0,
diff --git a/app/charts/map/map-legend.tsx b/app/charts/map/map-legend.tsx
index 7544e71c2..279011762 100644
--- a/app/charts/map/map-legend.tsx
+++ b/app/charts/map/map-legend.tsx
@@ -1,6 +1,5 @@
import {
axisBottom,
- interpolateOranges,
NumberValue,
range,
ScaleLinear,
@@ -14,6 +13,7 @@ import {
import * as React from "react";
import { useEffect, useMemo, useRef } from "react";
import { Box, Flex, Text } from "theme-ui";
+import { ColorRamp } from "../../configurator/components/chart-controls/color-ramp";
import {
getColorInterpolator,
useFormatInteger,
@@ -92,10 +92,18 @@ export const MapLegend = () => {
{areaLayer.measureLabel}
)}
- {areaLayer.paletteType === "continuous" && }
- {areaLayer.paletteType === "discrete" && }
- {areaLayer.paletteType === "quantile" && }
- {areaLayer.paletteType === "jenks" && }
+ {areaLayer.colorScaleInterpolationType === "linear" && (
+
+ )}
+ {areaLayer.colorScaleInterpolationType === "quantize" && (
+
+ )}
+ {areaLayer.colorScaleInterpolationType === "quantile" && (
+
+ )}
+ {areaLayer.colorScaleInterpolationType === "jenks" && (
+
+ )}
)}
@@ -509,7 +517,7 @@ const ContinuousColorLegend = () => {
width={width - MARGIN.left - MARGIN.right}
height={COLOR_RAMP_HEIGHT}
colorInterpolator={getColorInterpolator(palette)}
- nbClass={width}
+ nbClass={width - MARGIN.left - MARGIN.right}
/>
);
};
-
-const ColorRamp = ({
- colorInterpolator = interpolateOranges,
- nbClass,
- width,
- height,
-}: {
- colorInterpolator: (t: number) => string;
- nbClass: number;
- width: number;
- height: number;
-}) => {
- const canvasRef = useRef(null);
-
- useEffect(() => {
- const canvas = canvasRef.current;
- const context = canvas && canvas.getContext("2d");
-
- if (canvas && context) {
- context.clearRect(0, 0, width, height);
- canvas.style.imageRendering = "-moz-crisp-edges";
- canvas.style.imageRendering = "pixelated";
-
- for (let i = 0; i < nbClass; ++i) {
- context.fillStyle = colorInterpolator(i / (nbClass - 1));
- context.fillRect(i, 0, 1, height);
- }
- }
- });
-
- return ;
-};
diff --git a/app/charts/map/map-state.tsx b/app/charts/map/map-state.tsx
index 257398a64..f8daf6281 100644
--- a/app/charts/map/map-state.tsx
+++ b/app/charts/map/map-state.tsx
@@ -22,8 +22,10 @@ import {
} from "../../configurator/components/ui-helpers";
import {
BaseLayer,
+ ColorScaleInterpolationType,
+ DivergingPaletteType,
MapFields,
- PaletteType,
+ SequentialPaletteType,
} from "../../configurator/config-types";
import {
GeoData,
@@ -61,8 +63,8 @@ export interface MapState {
| ScaleQuantile
| ScaleLinear
| ScaleThreshold;
- paletteType: PaletteType;
- palette: string;
+ colorScaleInterpolationType: ColorScaleInterpolationType;
+ palette: DivergingPaletteType | SequentialPaletteType;
nbClass: number;
dataDomain: [number, number];
};
@@ -80,36 +82,38 @@ export interface MapState {
}
const getColorScale = ({
- paletteType,
+ scaleInterpolationType,
palette,
getValue,
data,
dataDomain,
nbClass,
}: {
- paletteType: PaletteType;
- palette: string;
+ scaleInterpolationType: ColorScaleInterpolationType;
+ palette: DivergingPaletteType | SequentialPaletteType;
getValue: (x: Observation) => number | null;
data: Observation[];
dataDomain: [number, number];
nbClass: number;
}) => {
- const paletteDomain = getSingleHueSequentialPalette({
- palette,
- nbClass: 9,
- });
+ const interpolator = getColorInterpolator(palette);
+ const getDiscreteRange = () => {
+ return Array.from({ length: nbClass }, (_, i) =>
+ interpolator(i / (nbClass - 1))
+ );
+ };
- switch (paletteType) {
- case "continuous":
- return scaleSequential(getColorInterpolator(palette)).domain(dataDomain);
- case "discrete":
+ switch (scaleInterpolationType) {
+ case "linear":
+ return scaleSequential(interpolator).domain(dataDomain);
+ case "quantize":
return scaleQuantize()
.domain(dataDomain)
- .range(getSingleHueSequentialPalette({ palette, nbClass }));
+ .range(getDiscreteRange());
case "quantile":
return scaleQuantile()
.domain(data.map((d) => getValue(d)))
- .range(getSingleHueSequentialPalette({ palette, nbClass }));
+ .range(getDiscreteRange());
case "jenks":
const ckMeansThresholds = ckmeans(
data.map((d) => getValue(d) ?? NaN),
@@ -118,8 +122,13 @@ const getColorScale = ({
return scaleThreshold()
.domain(ckMeansThresholds)
- .range(getSingleHueSequentialPalette({ palette, nbClass }));
+ .range(getDiscreteRange());
default:
+ const paletteDomain = getSingleHueSequentialPalette({
+ palette,
+ nbClass: 9,
+ });
+
return scaleLinear()
.domain(dataDomain)
.range([paletteDomain[0], paletteDomain[paletteDomain.length - 1]]);
@@ -140,7 +149,6 @@ const useMapState = ({
}): MapState => {
const width = useWidth();
const { areaLayer, symbolLayer } = fields;
- const { palette, nbClass, paletteType } = areaLayer;
const getAreaLabel = useStringVariable(areaLayer.componentIri);
const getSymbolLabel = useStringVariable(symbolLayer.componentIri);
@@ -227,12 +235,12 @@ const useMapState = ({
]) as [number, number];
const areaColorScale = getColorScale({
- paletteType,
- palette,
+ scaleInterpolationType: areaLayer.colorScaleInterpolationType,
+ palette: areaLayer.palette,
getValue: getAreaValue,
data: areaData,
dataDomain: areaDataDomain,
- nbClass,
+ nbClass: areaLayer.nbClass,
});
const getAreaColor = (v: number | null) => {
@@ -279,9 +287,9 @@ const useMapState = ({
getValue: getAreaValue,
getColor: getAreaColor,
colorScale: areaColorScale,
- paletteType,
- palette,
- nbClass: nbClass,
+ colorScaleInterpolationType: areaLayer.colorScaleInterpolationType,
+ palette: areaLayer.palette,
+ nbClass: areaLayer.nbClass,
dataDomain: areaDataDomain,
},
symbolLayer: {
diff --git a/app/configurator/components/chart-controls/color-palette.tsx b/app/configurator/components/chart-controls/color-palette.tsx
index bf9b8dae8..1854c067f 100644
--- a/app/configurator/components/chart-controls/color-palette.tsx
+++ b/app/configurator/components/chart-controls/color-palette.tsx
@@ -1,18 +1,18 @@
import { Trans } from "@lingui/macro";
-import { Box, Button, Flex, Text } from "theme-ui";
import { useSelect } from "downshift";
import get from "lodash/get";
import { useCallback } from "react";
+import { Box, Button, Flex, Text } from "theme-ui";
import { ConfiguratorStateConfiguringChart, useConfiguratorState } from "../..";
import { Label } from "../../../components/form";
+import { DimensionMetaDataFragment } from "../../../graphql/query-hooks";
+import { Icon } from "../../../icons";
import {
categoricalPalettes,
+ divergingSteppedPalettes,
getPalette,
mapColorsToComponentValuesIris,
- sequentialPalettes,
} from "../ui-helpers";
-import { DimensionMetaDataFragment } from "../../../graphql/query-hooks";
-import { Icon } from "../../../icons";
type Props = {
field: string;
@@ -31,7 +31,7 @@ export const ColorPalette = ({
const palettes =
component?.__typename === "Measure"
- ? sequentialPalettes
+ ? divergingSteppedPalettes
: categoricalPalettes;
const currentPaletteName = get(
@@ -73,34 +73,14 @@ export const ColorPalette = ({
});
return (
-
+