UNPKG

victory-pie

Version:
366 lines (363 loc) 13.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getYOffsetMultiplayerByAngle = exports.getYOffset = exports.getXOffsetMultiplayerByAngle = exports.getXOffset = exports.getLabelIndicatorPropsForLineSegment = exports.getBaseProps = exports.getAverage = void 0; var _defaults = _interopRequireDefault(require("lodash/defaults")); var _isPlainObject = _interopRequireDefault(require("lodash/isPlainObject")); var d3Shape = _interopRequireWildcard(require("victory-vendor/d3-shape")); var _victoryCore = require("victory-core"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* eslint no-magic-numbers: ["error", { "ignore": [-1, 0, 1, 2, 45, 90, 135, 180, 225, 270, 315, 360] }]*/ const checkForValidText = text => { if (text === undefined || text === null || _victoryCore.Helpers.isFunction(text)) { return text; } return `${text}`; }; const getColor = (style, colors, index) => { if (style && style.data && style.data.fill) { return style.data.fill; } return colors && colors[index % colors.length]; }; const getRadius = (props, padding) => { if (typeof props.radius === "number") { return props.radius; } return Math.min(props.width - padding.left - padding.right, props.height - padding.top - padding.bottom) / 2; }; const getOrigin = (props, padding) => { const { width, height } = props; const origin = (0, _isPlainObject.default)(props.origin) ? props.origin : {}; return { x: origin.x !== undefined ? origin.x : (padding.left - padding.right + width) / 2, y: origin.y !== undefined ? origin.y : (padding.top - padding.bottom + height) / 2 }; }; const getSlices = (props, data) => { const padAngle = _victoryCore.Helpers.isFunction(props.padAngle) ? 0 : props.padAngle; const layoutFunction = d3Shape.pie().sort(null).startAngle(_victoryCore.Helpers.degreesToRadians(props.startAngle)).endAngle(_victoryCore.Helpers.degreesToRadians(props.endAngle)).padAngle(_victoryCore.Helpers.degreesToRadians(padAngle)).value(datum => { return datum._y; }); return layoutFunction(data); }; const getCategoriesFromProps = props => Array.isArray(props.categories) ? props.categories : props?.categories?.x ?? []; /** * Sorts data by props.categories or props.categories.x. If all of the data keys aren't * included in categories, any remaining data will be appended to the data array. * If extraneous categories are included in the categories prop, the will be ignored and * have no effect on the rendered component. */ const getDataSortedByCategories = (props, data) => { const sorted = []; getCategoriesFromProps(props).forEach(category => { const idx = data.findIndex(_ref => { let { x } = _ref; return x === category; }); if (idx >= 0) { const datum = data.splice(idx, 1)[0]; sorted.push(datum); } }); return [...sorted, ...data]; }; const getCalculatedValues = props => { const { colorScale, theme } = props; const styleObject = _victoryCore.Helpers.getDefaultStyles(props, "pie"); const style = _victoryCore.Helpers.getStyles(props.style, styleObject); const colors = Array.isArray(colorScale) ? colorScale : _victoryCore.Style.getColorScale(colorScale, theme); const padding = _victoryCore.Helpers.getPadding(props.padding); const defaultRadius = getRadius(props, padding); const origin = getOrigin(props, padding); const data = getDataSortedByCategories(props, _victoryCore.Data.getData(props)); const slices = getSlices(props, data); return Object.assign({}, props, { style, colors, padding, defaultRadius, data, slices, origin }); }; const getSliceStyle = (index, calculatedValues) => { const { style, colors } = calculatedValues; const fill = getColor(style, colors, index); return Object.assign({ fill }, style.data); }; const getLabelText = (props, datum, index) => { let text; if (datum.label) { text = datum.label; } else if (Array.isArray(props.labels)) { text = props.labels[index]; } else { text = _victoryCore.Helpers.isFunction(props.labels) ? props.labels : datum.xName || datum._x; } return checkForValidText(text); }; const getLabelArc = labelRadius => { return d3Shape.arc().outerRadius(labelRadius).innerRadius(labelRadius); }; const getCalculatedLabelRadius = (radius, labelRadius, style) => { const padding = style && style.padding || 0; return labelRadius || radius + padding; }; const getLabelPosition = (arc, slice, position) => { const construct = { startAngle: position === "startAngle" ? slice.startAngle : slice.endAngle, endAngle: position === "endAngle" ? slice.endAngle : slice.startAngle }; const clonedArc = Object.assign({}, slice, construct); return arc.centroid(clonedArc); }; const getLabelOrientation = (degree, labelPlacement) => { if (labelPlacement === "perpendicular") { return degree > 90 && degree < 270 ? "bottom" : "top"; } else if (labelPlacement === "parallel") { return degree >= 0 && degree <= 180 ? "right" : "left"; } if (degree < 45 || degree > 315) { return "top"; } else if (degree >= 45 && degree < 135) { return "right"; } else if (degree >= 135 && degree < 225) { return "bottom"; } return "left"; }; const getTextAnchor = orientation => { if (orientation === "top" || orientation === "bottom") { return "middle"; } return orientation === "right" ? "start" : "end"; }; const getVerticalAnchor = orientation => { if (orientation === "left" || orientation === "right") { return "middle"; } return orientation === "bottom" ? "start" : "end"; }; const getBaseLabelAngle = (slice, labelPosition, labelStyle) => { let baseAngle = 0; if (labelPosition.angle !== undefined) { baseAngle = labelStyle.angle; } else if (labelPosition === "centroid") { baseAngle = _victoryCore.Helpers.radiansToDegrees((slice.startAngle + slice.endAngle) / 2); } else { baseAngle = labelPosition === "startAngle" ? _victoryCore.Helpers.radiansToDegrees(slice.startAngle) : _victoryCore.Helpers.radiansToDegrees(slice.endAngle); } const positiveAngle = baseAngle < 0 ? 360 - baseAngle : baseAngle; return positiveAngle % 360; }; const getLabelAngle = (baseAngle, labelPlacement) => { if (labelPlacement === "vertical") { return 0; } if (labelPlacement === "parallel") { return baseAngle > 180 && baseAngle < 360 ? baseAngle + 90 : baseAngle - 90; } return baseAngle > 90 && baseAngle < 270 ? baseAngle - 180 : baseAngle; }; const getLabelProps = (text, dataProps, calculatedValues) => { const { index, datum, data, slice, labelComponent, theme } = dataProps; const { style, defaultRadius, origin, width, height } = calculatedValues; const labelRadius = _victoryCore.Helpers.evaluateProp(calculatedValues.labelRadius, Object.assign({ text }, dataProps)); const labelPosition = _victoryCore.Helpers.evaluateProp(calculatedValues.labelPosition, Object.assign({ text }, dataProps)) || "centroid"; const labelPlacement = _victoryCore.Helpers.evaluateProp(calculatedValues.labelPlacement, Object.assign({ text }, dataProps)) || "vertical"; const labelStyle = Object.assign({ padding: 0 }, style.labels); const evaluatedStyle = _victoryCore.Helpers.evaluateStyle(labelStyle, Object.assign({ labelRadius, text }, dataProps)); const calculatedLabelRadius = getCalculatedLabelRadius(defaultRadius, labelRadius, evaluatedStyle); const labelArc = getLabelArc(calculatedLabelRadius); const position = getLabelPosition(labelArc, slice, labelPosition); const baseAngle = getBaseLabelAngle(slice, labelPosition, labelStyle); const labelAngle = getLabelAngle(baseAngle, labelPlacement); const orientation = getLabelOrientation(baseAngle, labelPlacement); const textAnchor = labelStyle.textAnchor || getTextAnchor(orientation); const verticalAnchor = labelStyle.verticalAnchor || getVerticalAnchor(orientation); const labelProps = { width, height, index, datum, data, slice, orientation, text, style: labelStyle, x: Math.round(position[0]) + origin.x, y: Math.round(position[1]) + origin.y, textAnchor, verticalAnchor, angle: labelAngle, calculatedLabelRadius }; if (!_victoryCore.Helpers.isTooltip(labelComponent)) { return labelProps; } const tooltipTheme = theme && theme.tooltip || {}; return (0, _defaults.default)({}, labelProps, _victoryCore.Helpers.omit(tooltipTheme, ["style"])); }; const getXOffsetMultiplayerByAngle = angle => Math.cos(angle - _victoryCore.Helpers.degreesToRadians(90)); exports.getXOffsetMultiplayerByAngle = getXOffsetMultiplayerByAngle; const getYOffsetMultiplayerByAngle = angle => Math.sin(angle - _victoryCore.Helpers.degreesToRadians(90)); exports.getYOffsetMultiplayerByAngle = getYOffsetMultiplayerByAngle; const getXOffset = (offset, angle) => offset * getXOffsetMultiplayerByAngle(angle); exports.getXOffset = getXOffset; const getYOffset = (offset, angle) => offset * getYOffsetMultiplayerByAngle(angle); exports.getYOffset = getYOffset; const getAverage = array => array.reduce((acc, cur) => acc + cur, 0) / array.length; exports.getAverage = getAverage; const getLabelIndicatorPropsForLineSegment = (props, calculatedValues, labelProps) => { const { innerRadius, radius, slice: { startAngle, endAngle }, labelIndicatorInnerOffset, labelIndicatorOuterOffset, index } = props; const { height, width } = calculatedValues; const { calculatedLabelRadius } = labelProps; // calculation const middleRadius = getAverage([innerRadius, radius]); const midAngle = getAverage([endAngle, startAngle]); const centerX = width / 2; const centerY = height / 2; const innerOffset = middleRadius + labelIndicatorInnerOffset; const outerOffset = calculatedLabelRadius - labelIndicatorOuterOffset; const x1 = centerX + getXOffset(innerOffset, midAngle); const y1 = centerY + getYOffset(innerOffset, midAngle); const x2 = centerX + getXOffset(outerOffset, midAngle); const y2 = centerY + getYOffset(outerOffset, midAngle); const labelIndicatorProps = { x1, y1, x2, y2, index }; return (0, _defaults.default)({}, labelIndicatorProps); }; exports.getLabelIndicatorPropsForLineSegment = getLabelIndicatorPropsForLineSegment; const getBaseProps = (initialProps, fallbackProps) => { const props = _victoryCore.Helpers.modifyProps(initialProps, fallbackProps, "pie"); const calculatedValues = getCalculatedValues(props); const { slices, style, data, origin, defaultRadius, labels, events, sharedEvents, height, width, standalone, name, innerRadius, cornerRadius, padAngle, disableInlineStyles, labelIndicator } = calculatedValues; const radius = props.radius || defaultRadius; const initialChildProps = { parent: { standalone, height, width, slices, name, style: style.parent } }; return slices.reduce((childProps, slice, index) => { const datum = (0, _defaults.default)({}, data[index], { startAngle: _victoryCore.Helpers.radiansToDegrees(slice.startAngle), endAngle: _victoryCore.Helpers.radiansToDegrees(slice.endAngle), padAngle: _victoryCore.Helpers.radiansToDegrees(slice.padAngle) }); const eventKey = !_victoryCore.Helpers.isNil(datum.eventKey) ? datum.eventKey : index; const dataProps = { index, slice, datum, data, origin, innerRadius, radius, cornerRadius, padAngle, style: disableInlineStyles ? {} : getSliceStyle(index, calculatedValues), disableInlineStyles }; childProps[eventKey] = { data: dataProps }; const text = getLabelText(props, datum, index); if (text !== undefined && text !== null || labels && (events || sharedEvents)) { const evaluatedText = _victoryCore.Helpers.evaluateProp(text, dataProps); childProps[eventKey].labels = getLabelProps(evaluatedText, Object.assign({}, props, dataProps), calculatedValues); if (labelIndicator) { const labelProps = childProps[eventKey].labels; if (labelProps.calculatedLabelRadius > radius) { childProps[eventKey].labelIndicators = getLabelIndicatorPropsForLineSegment(Object.assign({}, props, dataProps), calculatedValues, labelProps); } } } return childProps; }, initialChildProps); }; exports.getBaseProps = getBaseProps;