@apptane/react-ui-charts
Version:
Chart components in Apptane React UI framework
250 lines (210 loc) • 9.01 kB
JavaScript
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