UNPKG

@apptane/react-ui-charts

Version:
250 lines (210 loc) 9.01 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; const _excluded = ["pri", "sec", "bands", "color"]; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } import take from "lodash/take"; import { getColorMap, resolveMappedColor, resolvePaletteReference } from "@apptane/react-ui-core"; import { useMemo } from "react"; import { quantize } from "d3-interpolate"; import { scaleLinear, scaleQuantize } from "d3-scale"; import { getColorInterpolator, hex2rgba, mutedColor } from "../common/ColorScheme.js"; import { Domain } from "../common/Types.js"; import { ChartLinearAxis } from "../parts/ChartLinearAxis.js"; import { ChartLinearGrid } from "../parts/ChartLinearGrid.js"; import { jsx as _jsx } from "@emotion/react/jsx-runtime"; /** * Returns computed data for XY charts with numeric range. */ function useComputedData(scaleX, compareX, domainXType, _ref) { let { componentId, data, domainY, extentY, stacked, palette, colorMode, colorScheme, color: colorFn } = _ref; return useMemo(() => { var _domainY$slice; if (data == null || data.length === 0) { // if domainY is defined we shall return default scaleY // for the Y axis to be constructed using one const defaultScaleY = domainY != null && domainY.length === 2 ? scaleLinear().rangeRound([0, extentY]).domain(domainY.slice().reverse()) // [!] reversed domain .nice() : undefined; return [undefined, undefined, defaultScaleY]; } const prefix = "".concat(componentId, "-gradient-"); const count = data.length; // minimum number of colors to quantize the spectrum into const MIN_SHADES = 5; const back = colorMode === "dark" ? 16 : 255; let colorScale; if (colorScheme != null) { const interpolator = getColorInterpolator(palette, colorScheme); const reduced = t => interpolator(t * 0.8 + 0.1); // reduce range to avoid too light/dark colors colorScale = scaleQuantize(take(quantize(reduced, Math.max(count, MIN_SHADES)), count)).domain([0, count]); } else { const colors = getColorMap(palette, count).map(r => resolvePaletteReference(palette, r)); colorScale = scaleQuantize(take(colors, count)).domain([0, count]); } let minY; let maxY; const valuesX = new Set(); // tracks baseline for stacked series const baselinePri = stacked ? new Map() : undefined; const baselineSec = stacked ? new Map() : undefined; const computed = data.map((datum, datumIndex) => { const { pri, sec, bands, color } = datum, other = _objectWithoutProperties(datum, _excluded); let c = color; if (typeof colorFn === "function") { c = colorFn(datum); } // use series index to establish the color based on the color scheme if (c == null) { c = colorScale(datumIndex); } else { c = resolveMappedColor(palette, c); } function processValue(value, valueIndex, baseline) { var _baseline$get; const cx = scaleX(value.x); const by = cx != null ? (_baseline$get = baseline === null || baseline === void 0 ? void 0 : baseline.get(cx)) !== null && _baseline$get !== void 0 ? _baseline$get : 0 : 0; const y = by + value.y; valuesX.add(value.x); if (isFinite(y)) { // shift baseline up by the current series data if (baseline && cx != null) { baseline.set(cx, y); } if (minY == null || y < minY) { minY = y; } if (maxY == null || y > maxY) { maxY = y; } } return _objectSpread(_objectSpread({}, value), {}, { index: valueIndex, stackedY: y, c: cx != null ? { x: cx, y: NaN, v: NaN } : undefined }); } const priEx = pri.map((p, i) => processValue(p, i, baselinePri)); const secEx = sec === null || sec === void 0 ? void 0 : sec.map((p, i) => processValue(p, i, baselineSec)); const bandsEx = stacked ? undefined : bands === null || bands === void 0 ? void 0 : bands.map((b, bandIndex) => { const cx = scaleX(b.x); return _objectSpread(_objectSpread({}, b), {}, { index: bandIndex, c: cx != null ? { x: cx, y0: NaN, y1: NaN } : undefined }); }); return _objectSpread(_objectSpread({}, other), {}, { index: datumIndex, color: c, areaColor: hex2rgba(c), loColor: mutedColor(c, 0.2, back), hiColor: mutedColor(c, 0.5, back), gradientId: "".concat(prefix).concat(c.replace("#", "")), pri: priEx, sec: secEx, bands: bandsEx }); }); const realDomainY = (_domainY$slice = domainY === null || domainY === void 0 ? void 0 : domainY.slice()) !== null && _domainY$slice !== void 0 ? _domainY$slice : []; if (minY != null && realDomainY[0] == null) { realDomainY[0] = minY; } if (maxY != null && realDomainY[1] == null) { realDomainY[1] = maxY; } // [!] reversed domain to align with SVG coordinate const scaleY = scaleLinear().rangeRound([0, extentY]).domain(realDomainY.reverse()).nice(); // second pass to generate Y coordinate once scale has been established computed.forEach(datum => { var _datum$bands; [datum.pri, datum.sec].forEach(_ => _ === null || _ === void 0 ? void 0 : _.forEach(value => { if (value.c != null) { if (isFinite(value.stackedY)) { value.c.y = scaleY(value.stackedY); value.c.v = scaleY(value.y); } else { value.c = undefined; } } })); (_datum$bands = datum.bands) === null || _datum$bands === void 0 ? void 0 : _datum$bands.forEach(band => { if (band.c != null) { if (isFinite(band.y0) && isFinite(band.y1)) { band.c.y0 = scaleY(band.y0); band.c.y1 = scaleY(band.y1); } else { band.c = undefined; } } }); }); const domain = new Domain(Array.from(valuesX.values()), compareX, domainXType === "ordinal"); return [computed, domain, scaleY]; }, [componentId, data, domainY, extentY, stacked, scaleX, compareX, domainXType, palette, colorScheme, colorMode, colorFn]); } /** * Generates puzzle pieces for XY pane with numeric range. */ export function useXYPaneData(context, props) { const [computed, domainX, scaleY] = useComputedData(context.scaleX, context.compareX, context.domainType, props); const axisY = scaleY && _jsx(ChartLinearAxis, { orientation: "y", componentId: props.componentId, theme: props.theme, colorMode: props.colorMode, span: props.axisYWidth, textOffset: 1, tickSize: props.axisYWidth - 4, axisVisible: false, tickVisible: true, tickValues: props.axisYValues, format: props.formatYDomain, scale: scaleY }, "axisY"); const gridY = scaleY && props.gridYVisible && _jsx(ChartLinearGrid, { orientation: "horizontal", componentId: props.componentId, theme: props.theme, colorMode: props.colorMode, left: props.axisYWidth, width: props.extentX, height: props.extentY, tickValues: props.axisYValues, scale: scaleY }, "gridY"); const gridX = props.gridXVisible && props.gridX(props); return [computed, domainX, scaleY, [axisY, gridY, gridX]]; } const DefaultFormatNumericLocaleOptions = { maximumFractionDigits: 0 }; const defaultFormatNumeric = v => v.toLocaleString(undefined, DefaultFormatNumericLocaleOptions); /** * Default formatting function for numeric values in the tooltip. */ export function formatNumericTooltip(v, lb, ub) { const formattedValue = defaultFormatNumeric(v); if (lb != null && ub != null) { return "".concat(formattedValue, " (").concat(defaultFormatNumeric(lb), "\u2014").concat(defaultFormatNumeric(ub), ")"); } return formattedValue; } //# sourceMappingURL=commonXY.js.map