UNPKG

@apptane/react-ui-charts

Version:
204 lines (169 loc) 7.8 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; const _excluded = ["pri", "sec", "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 { forceCollide, forceSimulation, forceX, forceY } from "d3-force"; import { quantize } from "d3-interpolate"; import { scaleLinear, scaleQuantize } from "d3-scale"; import { getColorInterpolator, mutedColor } from "../common/ColorScheme.js"; import { Domain } from "../common/Types.js"; const ITERATIONS = 60; function useComputedData(scaleX, compareX, domainXType, scaleY, compareY, domainYType, minDomainZ, maxDomainZ, minExtentZ, maxExtentZ, _ref, exact) { let { data, palette, colorMode, colorScheme, color: colorFn } = _ref; return useMemo(() => { var _ref2, _ref3; if (data == null || data.length === 0) { return [undefined, undefined, undefined, undefined]; } 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 minZ; let maxZ; const valuesX = new Set(); const valuesY = new Set(); const computed = data.map((datum, datumIndex) => { const { pri, sec, 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) { const cx = scaleX(value.x); const cy = scaleY(value.y); valuesX.add(value.x); valuesY.add(value.y); if (value.z != null && isFinite(value.z)) { if (minZ == null || value.z < minZ) { minZ = value.z; } if (maxZ == null || value.z > maxZ) { maxZ = value.z; } } return _objectSpread(_objectSpread({}, value), {}, { index: valueIndex, c: cx != null && cy != null ? { x: cx, y: cy, d: NaN } : undefined }); } const priEx = pri.map((p, i) => processValue(p, i)); const secEx = sec === null || sec === void 0 ? void 0 : sec.map((p, i) => processValue(p, i)); return _objectSpread(_objectSpread({}, other), {}, { index: datumIndex, color: c, loColor: mutedColor(c, 0.2, back), hiColor: mutedColor(c, 0.5, back), pri: priEx, sec: secEx }); }); const scaleZ = scaleLinear().rangeRound([minExtentZ, Math.round(maxExtentZ / Math.sqrt(data.length))]).domain([(_ref2 = minDomainZ !== null && minDomainZ !== void 0 ? minDomainZ : minZ) !== null && _ref2 !== void 0 ? _ref2 : 0, (_ref3 = maxDomainZ !== null && maxDomainZ !== void 0 ? maxDomainZ : maxZ) !== null && _ref3 !== void 0 ? _ref3 : 0]); // second pass to generate node sizes computed.forEach(datum => [datum.pri, datum.sec].forEach(_ => _ === null || _ === void 0 ? void 0 : _.forEach(value => { if (value.c != null) { if (value.z != null && isFinite(value.z)) { value.c.d = scaleZ(value.z); } else { value.c = undefined; } } }))); // use force simulation to compute positioning if (!exact) { const nodes = []; computed.forEach(datum => [datum.pri, datum.sec].forEach((_, i) => _ === null || _ === void 0 ? void 0 : _.forEach(value => { if (value.c != null) { nodes.push({ datumIndex: datum.index, valueIndex: value.index, valueType: i === 0 ? "pri" : "sec", valueData: value.c }); } }))); const spacing = 0.5; const fc = forceCollide(d => d.valueData.d * 0.5 + spacing); const fx = forceX(d => d.valueData.x).strength(0.1); const fy = forceY(d => d.valueData.y).strength(0.1); const simulation = forceSimulation(nodes).force("x", fx).force("y", fy).force("collide", fc).stop(); simulation.tick(ITERATIONS); simulation.nodes().forEach(node => { const datum = computed[node.datumIndex]; const value = node.valueType === "pri" ? datum.pri[node.valueIndex] : datum.sec != null ? datum.sec[node.valueIndex] : undefined; if (value && value.c != null && node.x != null && node.y != null) { value.c.x = node.x; value.c.y = node.y; } }); } const domainX = new Domain(Array.from(valuesX.values()), compareX, domainXType === "ordinal"); const domainY = new Domain(Array.from(valuesY.values()), compareY, domainYType === "ordinal"); return [computed, domainX, domainY, scaleZ]; }, [data, minExtentZ, maxExtentZ, minDomainZ, maxDomainZ, scaleX, compareX, domainXType, scaleY, compareY, domainYType, palette, colorScheme, colorMode, colorFn, exact]); } /** * Generates puzzle pieces for XY pane with Z dimension. */ export function useXYZPaneData(context, scaleY, compareY, domainYType, minDomainZ, maxDomainZ, minExtentZ, maxExtentZ, props, exact) { const [computed, domainX, domainY, scaleZ] = useComputedData(context.scaleX, context.compareX, context.domainType, scaleY, compareY, domainYType, minDomainZ, maxDomainZ, minExtentZ, maxExtentZ, props, exact); return [computed, domainX, domainY, scaleZ, []]; } /** * Finds bubble datum via (X,Y) coordinates. */ export function findDatum(cx, cy, data) { function match(values) { for (let j = 0; j < values.length; ++j) { const p = values[j]; if (p != null) { const _p = p; if (_p.c != null) { const distance = Math.pow(_p.c.d * 0.5, 2); if (Math.pow(_p.c.x - cx, 2) < distance && Math.pow(_p.c.y - cy, 2) < distance) { return true; } } } } return false; } for (let i = 0; i < data.length; ++i) { const d = data[i]; if (match(d.pri) || d.sec != null && match(d.sec)) { return d; } } return undefined; } //# sourceMappingURL=commonXYZ.js.map