victory-voronoi-container
Version:
Interactive Voronoi Mouseover Component for Victory
242 lines (240 loc) • 8.53 kB
JavaScript
"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();