UNPKG

victory-voronoi-container

Version:

Interactive Voronoi Mouseover Component for Victory

242 lines (240 loc) 8.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.VoronoiHelpers = void 0; var _victoryCore = require("victory-core"); var _isEmpty = _interopRequireDefault(require("lodash/isEmpty")); var _isRegExp = _interopRequireDefault(require("lodash/isRegExp")); var _throttle = _interopRequireDefault(require("lodash/throttle")); var _reactFastCompare = _interopRequireDefault(require("react-fast-compare")); var _index = _interopRequireDefault(require("delaunay-find/lib/index.js")); var _react = _interopRequireDefault(require("react")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const ON_MOUSE_MOVE_THROTTLE_MS = 32; class VoronoiHelpersClass { withinBounds(props, point) { const { width, height, polar, origin, scale } = props; const padding = _victoryCore.Helpers.getPadding(props.voronoiPadding); const { x, y } = point; if (polar) { const distanceSquared = Math.pow(x - origin.x, 2) + Math.pow(y - origin.y, 2); const radius = Math.max(...scale.y.range()); return distanceSquared < Math.pow(radius, 2); } return x >= padding.left && x <= width - padding.right && y >= padding.top && y <= height - padding.bottom; } getDatasets(props) { const minDomain = { x: _victoryCore.Collection.getMinValue(props.domain.x), y: _victoryCore.Collection.getMinValue(props.domain.y) }; const children = _react.default.Children.toArray(props.children); const addMeta = (data, name, child) => { const continuous = child && child.type && child.type.continuous; const style = child ? child.props && child.props.style : props.style; return data.map((datum, index) => { const { x, y, y0, x0 } = _victoryCore.Helpers.getPoint(datum); const voronoiX = (Number(x) + Number(x0)) / 2; const voronoiY = (Number(y) + Number(y0)) / 2; return Object.assign({ _voronoiX: props.voronoiDimension === "y" ? minDomain.x : voronoiX, _voronoiY: props.voronoiDimension === "x" ? minDomain.y : voronoiY, eventKey: index, childName: name, continuous, style }, datum); }); }; if (props.data) { return addMeta(props.data); } const getData = childProps => { const data = _victoryCore.Data.getData(childProps); return Array.isArray(data) && data.length > 0 ? data : undefined; }; const iteratee = (child, childName) => { const childProps = child.props || {}; const name = childProps.name || childName; const blacklist = props.voronoiBlacklist || []; const blacklistStr = blacklist.filter(value => !!value && typeof value.valueOf() === "string"); const blacklistRegExp = blacklist.filter(_isRegExp.default); const isRegExpMatch = blacklistRegExp.some(regExp => regExp.test(name)); if (!_victoryCore.Data.isDataComponent(child) || blacklistStr.includes(name) || isRegExpMatch) { return null; } const getChildData = child.type && _victoryCore.Helpers.isFunction(child.type.getData) ? child.type.getData : getData; const childData = getChildData(child.props); return childData ? addMeta(childData, name, child) : null; }; return _victoryCore.Helpers.reduceChildren(children, iteratee, props); } findPoints(datasets, point) { return datasets.filter(d => { return point._voronoiX === d._voronoiX && point._voronoiY === d._voronoiY; }); } withinRadius(point, mousePosition, radius) { if (!point) { return false; } if (!radius) { return true; } const { x, y } = mousePosition; const distanceSquared = Math.pow(x - point[0], 2) + Math.pow(y - point[1], 2); return distanceSquared < Math.pow(radius, 2); } getVoronoiPoints(props, mousePosition) { const datasets = this.getDatasets(props); const scaledData = datasets.map(d => { const { x, y } = _victoryCore.Helpers.scalePoint(props, d); return [x, y]; }); const delaunay = _index.default.from(scaledData); const index = delaunay.find(mousePosition.x, mousePosition.y); const withinRadius = this.withinRadius(scaledData[index], mousePosition, props.radius); const points = withinRadius ? this.findPoints(datasets, datasets[index]) : []; return { points, index }; } getActiveMutations(props, point) { const { childName, continuous } = point; const { activateData, activateLabels, labels } = props; if (!activateData && !activateLabels) { return []; } const defaultTarget = activateData ? ["data"] : []; const targets = labels && !activateLabels ? defaultTarget : defaultTarget.concat("labels"); if ((0, _isEmpty.default)(targets)) { return []; } return targets.map(target => { const eventKey = continuous === true && target === "data" ? "all" : point.eventKey; return { childName, eventKey, target, mutation: () => ({ active: true }) }; }); } getInactiveMutations(props, point) { const { childName, continuous } = point; const { activateData, activateLabels, labels } = props; if (!activateData && !activateLabels) { return []; } const defaultTarget = activateData ? ["data"] : []; const targets = labels && !activateLabels ? defaultTarget : defaultTarget.concat("labels"); if ((0, _isEmpty.default)(targets)) { return []; } return targets.map(target => { const eventKey = continuous && target === "data" ? "all" : point.eventKey; return { childName, eventKey, target, mutation: () => null }; }); } // eslint-disable-next-line max-params getParentMutation(activePoints, mousePosition, parentSVG, vIndex) { return [{ target: "parent", eventKey: "parent", mutation: () => ({ activePoints, mousePosition, parentSVG, vIndex }) }]; } onActivated(props, points) { if (_victoryCore.Helpers.isFunction(props.onActivated)) { props.onActivated(points, props); } } onDeactivated(props, points) { if (_victoryCore.Helpers.isFunction(props.onDeactivated)) { props.onDeactivated(points, props); } } onMouseLeave = (evt, targetProps) => { this.onMouseMove.cancel(); const activePoints = targetProps.activePoints || []; this.onDeactivated(targetProps, activePoints); const inactiveMutations = activePoints.length ? activePoints.map(point => this.getInactiveMutations(targetProps, point)) : []; return this.getParentMutation([]).concat(...inactiveMutations); }; handleMouseMove = (evt, targetProps) => { const activePoints = targetProps.activePoints || []; const parentSVG = targetProps.parentSVG || _victoryCore.Selection.getParentSVG(evt); const mousePosition = _victoryCore.Selection.getSVGEventCoordinates(evt, parentSVG); if (!this.withinBounds(targetProps, mousePosition)) { this.onDeactivated(targetProps, activePoints); const inactiveMutations = activePoints.length ? activePoints.map(point => this.getInactiveMutations(targetProps, point)) : []; return this.getParentMutation([], mousePosition, parentSVG).concat(...inactiveMutations); } const { points = [], index } = this.getVoronoiPoints(targetProps, mousePosition); const parentMutations = this.getParentMutation(points, mousePosition, parentSVG, index); if (activePoints.length && (0, _reactFastCompare.default)(points, activePoints)) { return parentMutations; } this.onActivated(targetProps, points); this.onDeactivated(targetProps, activePoints); const activeMutations = points.length ? points.map(point => this.getActiveMutations(targetProps, point)) : []; const inactiveMutations = activePoints.length ? activePoints.map(point => this.getInactiveMutations(targetProps, point)) : []; return parentMutations.concat(...inactiveMutations, ...activeMutations); }; onMouseMove = (0, _throttle.default)(this.handleMouseMove, ON_MOUSE_MOVE_THROTTLE_MS, { leading: true, trailing: false }); } const VoronoiHelpers = exports.VoronoiHelpers = new VoronoiHelpersClass();