UNPKG

victory-legend

Version:
360 lines (358 loc) 11.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDimensions = exports.getBaseProps = void 0; var _defaults = _interopRequireDefault(require("lodash/defaults")); var _groupBy = _interopRequireDefault(require("lodash/groupBy")); var _range = _interopRequireDefault(require("lodash/range")); var _victoryCore = require("victory-core"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const getColorScale = props => { const { colorScale, theme } = props; return typeof colorScale === "string" ? _victoryCore.Style.getColorScale(colorScale, theme) : colorScale || []; }; const getLabelStyles = props => { const { data, style } = props; return data.map((datum, index) => { const baseLabelStyles = (0, _defaults.default)({}, datum.labels, style.labels); return _victoryCore.Helpers.evaluateStyle(baseLabelStyles, { datum, index, data }); }); }; const getStyles = function (props, styleObject) { if (styleObject === void 0) { styleObject = {}; } const style = props.style || {}; const parentStyleProps = { height: "100%", width: "100%" }; return { parent: (0, _defaults.default)(style.parent, styleObject.parent, parentStyleProps), data: (0, _defaults.default)({}, style.data, styleObject.data), labels: (0, _defaults.default)({}, style.labels, styleObject.labels), border: (0, _defaults.default)({}, style.border, styleObject.border), title: (0, _defaults.default)({}, style.title, styleObject.title) }; }; const getCalculatedValues = props => { const { orientation, theme } = props; const defaultStyles = theme && theme.legend && theme.legend.style ? theme.legend.style : {}; const style = getStyles(props, defaultStyles); const colorScale = getColorScale(props); const isHorizontal = orientation === "horizontal"; const borderPadding = _victoryCore.Helpers.getPadding(props.borderPadding); return Object.assign({}, props, { style, isHorizontal, colorScale, borderPadding }); }; const getColumn = (props, index) => { const { itemsPerRow, isHorizontal } = props; if (!itemsPerRow) { return isHorizontal ? index : 0; } return isHorizontal ? index % itemsPerRow : Math.floor(index / itemsPerRow); }; const getRow = (props, index) => { const { itemsPerRow, isHorizontal } = props; if (!itemsPerRow) { return isHorizontal ? 0 : index; } return isHorizontal ? Math.floor(index / itemsPerRow) : index % itemsPerRow; }; const groupData = props => { const { data } = props; const style = props.style && props.style.data || {}; const labelStyles = getLabelStyles(props); return data.map((datum, index) => { const symbol = datum.symbol || {}; const { fontSize } = labelStyles[index]; // eslint-disable-next-line no-magic-numbers const size = symbol.size || style.size || fontSize / 2.5; const symbolSpacer = props.symbolSpacer || Math.max(size, fontSize); return { ...datum, size, symbolSpacer, fontSize, textSize: _victoryCore.TextSize.approximateTextSize(datum.name, labelStyles[index]), column: getColumn(props, index), row: getRow(props, index) }; }); }; const getColumnWidths = (props, data) => { const gutter = props.gutter || {}; const gutterWidth = typeof gutter === "object" ? (gutter.left || 0) + (gutter.right || 0) : gutter || 0; const dataByColumn = (0, _groupBy.default)(data, "column"); const columns = Object.keys(dataByColumn); return columns.reduce((memo, curr, index) => { const lengths = dataByColumn[curr].map(d => { return d.textSize.width + d.size + d.symbolSpacer + gutterWidth; }); memo[index] = Math.max(...lengths); return memo; }, []); }; const getRowHeights = (props, data) => { const gutter = props.rowGutter || {}; const gutterHeight = typeof gutter === "object" ? (gutter.top || 0) + (gutter.bottom || 0) : gutter || 0; const dataByRow = (0, _groupBy.default)(data, "row"); return Object.keys(dataByRow).reduce((memo, curr, index) => { const rows = dataByRow[curr]; const lengths = rows.map(d => { return d.textSize.height + d.symbolSpacer + gutterHeight; }); memo[index] = Math.max(...lengths); return memo; }, []); }; const getTitleDimensions = props => { const style = props.style && props.style.title || {}; const textSize = _victoryCore.TextSize.approximateTextSize(props.title, style); const padding = style.padding || 0; return { height: textSize.height + 2 * padding || 0, width: textSize.width + 2 * padding || 0 }; }; const getOffset = (datum, rowHeights, columnWidths) => { const { column, row } = datum; return { x: (0, _range.default)(column).reduce((memo, curr) => memo + columnWidths[curr], 0), y: (0, _range.default)(row).reduce((memo, curr) => memo + rowHeights[curr], 0) }; }; const getAnchors = (titleOrientation, centerTitle) => { const standardAnchors = { textAnchor: titleOrientation === "right" ? "end" : "start", verticalAnchor: titleOrientation === "bottom" ? "end" : "start" }; if (centerTitle) { const horizontal = titleOrientation === "top" || titleOrientation === "bottom"; return { textAnchor: horizontal ? "middle" : standardAnchors.textAnchor, verticalAnchor: horizontal ? standardAnchors.verticalAnchor : "middle" }; } return standardAnchors; }; const getTitleStyle = props => { const { titleOrientation, centerTitle, titleComponent } = props; const baseStyle = props.style && props.style.title || {}; const componentStyle = titleComponent.props && titleComponent.props.style || {}; const anchors = getAnchors(titleOrientation, centerTitle); return Array.isArray(componentStyle) ? componentStyle.map(obj => (0, _defaults.default)({}, obj, baseStyle, anchors)) : (0, _defaults.default)({}, componentStyle, baseStyle, anchors); }; const getTitleProps = (props, borderProps) => { const { title, titleOrientation, centerTitle, borderPadding } = props; const { height, width } = borderProps; const style = getTitleStyle(props); const padding = Array.isArray(style) ? style[0].padding : style.padding; const horizontal = titleOrientation === "top" || titleOrientation === "bottom"; const xOrientation = titleOrientation === "bottom" ? "bottom" : "top"; const yOrientation = titleOrientation === "right" ? "right" : "left"; const standardPadding = { x: centerTitle ? width / 2 : borderPadding[xOrientation] + (padding || 0), y: centerTitle ? height / 2 : borderPadding[yOrientation] + (padding || 0) }; const getPadding = () => { return borderPadding[titleOrientation] + (padding || 0); }; const xOffset = horizontal ? standardPadding.x : getPadding(); const yOffset = horizontal ? getPadding() : standardPadding.y; return { x: titleOrientation === "right" ? props.x + width - xOffset : props.x + xOffset, y: titleOrientation === "bottom" ? props.y + height - yOffset : props.y + yOffset, style, text: title }; }; const getBorderProps = (props, contentHeight, contentWidth) => { const { x, y, borderPadding, style } = props; const height = (contentHeight || 0) + borderPadding.top + borderPadding.bottom; const width = (contentWidth || 0) + borderPadding.left + borderPadding.right; return { x, y, height, width, style: Object.assign({ fill: "none" }, style.border) }; }; const getDimensions = (initialProps, fallbackProps) => { const modifiedProps = _victoryCore.Helpers.modifyProps(initialProps, fallbackProps, "legend"); const props = Object.assign({}, modifiedProps, getCalculatedValues(modifiedProps)); const { title, titleOrientation } = props; const groupedData = groupData(props); const columnWidths = getColumnWidths(props, groupedData); const rowHeights = getRowHeights(props, groupedData); const titleDimensions = title ? getTitleDimensions(props) : { height: 0, width: 0 }; return { height: titleOrientation === "left" || titleOrientation === "right" ? Math.max(sum(rowHeights), titleDimensions.height) : sum(rowHeights) + titleDimensions.height, width: titleOrientation === "left" || titleOrientation === "right" ? sum(columnWidths) + titleDimensions.width : Math.max(sum(columnWidths), titleDimensions.width) }; }; exports.getDimensions = getDimensions; const getBaseProps = (initialProps, fallbackProps) => { const modifiedProps = _victoryCore.Helpers.modifyProps(initialProps, fallbackProps, "legend"); const props = Object.assign({}, modifiedProps, getCalculatedValues(modifiedProps)); const { data, standalone, theme, padding, style, colorScale, gutter, rowGutter, borderPadding, title, titleOrientation, name, x = 0, y = 0 } = props; const groupedData = groupData(props); const columnWidths = getColumnWidths(props, groupedData); const rowHeights = getRowHeights(props, groupedData); const labelStyles = getLabelStyles(props); const titleDimensions = title ? getTitleDimensions(props) : { height: 0, width: 0 }; const titleOffset = { x: titleOrientation === "left" ? titleDimensions.width : 0, y: titleOrientation === "top" ? titleDimensions.height : 0 }; const gutterOffset = { x: gutter && typeof gutter === "object" ? gutter.left || 0 : 0, y: rowGutter && typeof rowGutter === "object" ? rowGutter.top || 0 : 0 }; const { height, width } = getDimensions(props, fallbackProps); const borderProps = getBorderProps(props, height, width); const titleProps = getTitleProps(props, borderProps); const initialChildProps = { parent: { data, standalone, theme, padding, name, height: props.height, width: props.width, style: style.parent }, all: { border: borderProps, title: titleProps } }; return groupedData.reduce((childProps, datum, i) => { const color = colorScale[i % colorScale.length]; const dataStyle = (0, _defaults.default)({}, datum.symbol, style.data, { fill: color }); const eventKey = !_victoryCore.Helpers.isNil(datum.eventKey) ? datum.eventKey : i; const offset = getOffset(datum, rowHeights, columnWidths); const originY = y + borderPadding.top + datum.symbolSpacer; const originX = x + borderPadding.left + datum.symbolSpacer; const dataProps = { index: i, data, datum, symbol: dataStyle.type || dataStyle.symbol || "circle", size: datum.size, style: dataStyle, y: originY + offset.y + titleOffset.y + gutterOffset.y, x: originX + offset.x + titleOffset.x + gutterOffset.x }; const labelProps = { datum, data, text: datum.name, style: labelStyles[i], y: dataProps.y, x: dataProps.x + datum.symbolSpacer + datum.size / 2 }; childProps[eventKey] = { data: dataProps, labels: labelProps }; return childProps; }, initialChildProps); }; /** * Computes the sum of the values in `array`. * @param {Array} array The array to iterate over. * @returns {number} Returns the sum. */ exports.getBaseProps = getBaseProps; function sum(array) { if (array && array.length) { let value = 0; for (let i = 0; i < array.length; i++) { value += array[i]; } return value; } return 0; }