UNPKG

@dotconnor/grommet

Version:

focus on the essential experience

510 lines (424 loc) 19.5 kB
"use strict"; exports.__esModule = true; exports.Chart = void 0; var _react = _interopRequireWildcard(require("react")); var _styledComponents = require("styled-components"); var _defaultProps = require("../../default-props"); var _utils = require("../../utils"); var _StyledChart = require("./StyledChart"); var _utils2 = require("./utils"); function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } var gradientMaskColor = '#ffffff'; // use constants so re-renders don't re-trigger effects var defaultSize = { height: 'small', width: 'medium' }; var defaultValues = []; var Chart = /*#__PURE__*/_react["default"].forwardRef(function (_ref, ref) { var a11yTitle = _ref.a11yTitle, propsBounds = _ref.bounds, color = _ref.color, dash = _ref.dash, gap = _ref.gap, id = _ref.id, onClick = _ref.onClick, onHover = _ref.onHover, propsOpacity = _ref.opacity, _ref$overflow = _ref.overflow, overflow = _ref$overflow === void 0 ? false : _ref$overflow, pad = _ref.pad, point = _ref.point, round = _ref.round, _ref$size = _ref.size, propsSize = _ref$size === void 0 ? defaultSize : _ref$size, _ref$thickness = _ref.thickness, thickness = _ref$thickness === void 0 ? 'medium' : _ref$thickness, _ref$type = _ref.type, type = _ref$type === void 0 ? 'bar' : _ref$type, _ref$values = _ref.values, propsValues = _ref$values === void 0 ? defaultValues : _ref$values, rest = _objectWithoutPropertiesLoose(_ref, ["a11yTitle", "bounds", "color", "dash", "gap", "id", "onClick", "onHover", "opacity", "overflow", "pad", "point", "round", "size", "thickness", "type", "values"]); var containerRef = (0, _utils.useForwardedRef)(ref); var theme = (0, _react.useContext)(_styledComponents.ThemeContext) || _defaultProps.defaultProps.theme; // normalize variables var values = (0, _react.useMemo)(function () { return (0, _utils2.normalizeValues)(propsValues); }, [propsValues]); var bounds = (0, _react.useMemo)(function () { return (0, _utils2.normalizeBounds)(propsBounds, values); }, [propsBounds, values]); var strokeWidth = (0, _react.useMemo)(function () { return (0, _utils.parseMetricToNum)(theme.global.edgeSize[thickness] || thickness); }, [theme.global.edgeSize, thickness]); var inset = (0, _react.useMemo)(function () { var result = [0, 0, 0, 0]; if (pad) { if (pad.horizontal) { var padSize = (0, _utils.parseMetricToNum)(theme.global.edgeSize[pad.horizontal]); result[0] += padSize; result[2] += padSize; } if (pad.vertical) { var _padSize = (0, _utils.parseMetricToNum)(theme.global.edgeSize[pad.vertical]); result[1] += _padSize; result[3] += _padSize; } if (typeof pad === 'string') { var _padSize2 = (0, _utils.parseMetricToNum)(theme.global.edgeSize[pad]); result = [_padSize2, _padSize2, _padSize2, _padSize2]; } } return result; }, [pad, theme.global.edgeSize]); var strokeDasharray = (0, _react.useMemo)(function () { if (dash) { if (round) return strokeWidth + " " + strokeWidth * 1.5; return strokeWidth * 2 + " " + strokeWidth / 2; } return undefined; }, [dash, round, strokeWidth]); // potentially dynamic sizing var _useState = (0, _react.useState)([0, 0]), containerSize = _useState[0], setContainerSize = _useState[1]; var needContainerSize = (0, _react.useMemo)(function () { return propsSize && (propsSize === 'full' || propsSize === 'fill' || propsSize.height === 'full' || propsSize.height === 'fill' || propsSize.width === 'full' || propsSize.width === 'fill'); }, [propsSize]); var size = (0, _react.useMemo)(function () { var gapWidth = gap ? (0, _utils.parseMetricToNum)(theme.global.edgeSize[gap] || gap) : strokeWidth; // autoWidth is how wide we'd pefer var autoWidth = strokeWidth * values.length + (values.length - 1) * gapWidth; var sizeWidth = typeof propsSize === 'string' ? propsSize : propsSize.width || defaultSize.width; var width; if (sizeWidth === 'full' || sizeWidth === 'fill') { width = containerSize[0]; } else if (sizeWidth === 'auto') { width = autoWidth; } else { width = (0, _utils.parseMetricToNum)(theme.global.size[sizeWidth] || sizeWidth); } var sizeHeight = typeof propsSize === 'string' ? propsSize : propsSize.height || defaultSize.height; var height; if (sizeHeight === 'full' || sizeHeight === 'fill') { height = containerSize[1]; } else { height = (0, _utils.parseMetricToNum)(theme.global.size[sizeHeight] || sizeHeight); } return [width, height]; }, [containerSize, gap, propsSize, strokeWidth, theme.global.edgeSize, theme.global.size, values]); var scale = (0, _react.useMemo)(function () { return [(size[0] - (inset[0] + inset[2])) / (bounds[0][1] - bounds[0][0]), (size[1] - (inset[1] + inset[3])) / (bounds[1][1] - bounds[1][0])]; }, [bounds, inset, size]); var viewBounds = (0, _react.useMemo)(function () { return overflow ? [0, 0, size[0], size[1]] : [-(strokeWidth / 2), -(strokeWidth / 2), size[0] + strokeWidth, size[1] + strokeWidth]; }, [overflow, size, strokeWidth]); var useGradient = color && Array.isArray(color); // set container size when we get ref or when size changes (0, _react.useLayoutEffect)(function () { if (containerRef.current && needContainerSize) { var containerNode = containerRef.current; if (containerNode) { var parentNode = containerNode.parentNode; if (parentNode) { var rect = parentNode.getBoundingClientRect(); if (rect.width !== containerSize[0] || rect.height !== containerSize[1]) { setContainerSize([rect.width, rect.height]); } } } } }, [containerRef, containerSize, needContainerSize]); // container size, if needed (0, _react.useEffect)(function () { var onResize = function onResize() { var parentNode = containerRef.current.parentNode; var rect = parentNode.getBoundingClientRect(); setContainerSize([rect.width, rect.height]); }; if (needContainerSize) { window.addEventListener('resize', onResize); return function () { return window.removeEventListener('resize', onResize); }; } return undefined; }, [containerRef, needContainerSize]); // Converts values to drawing coordinates. // Takes into account the bounds, any inset, and the scale. var valueToCoordinate = function valueToCoordinate(xValue, yValue) { return [(xValue - bounds[0][0]) * scale[0] + inset[0], size[1] - ((yValue - bounds[1][0]) * scale[1] + inset[1])]; }; var renderBars = function renderBars() { return (values || []).filter(function (_ref2) { var value = _ref2.value; return value[1] !== undefined; }).map(function (valueArg, index) { var valueColor = valueArg.color, label = valueArg.label, valueOnHover = valueArg.onHover, valueOpacity = valueArg.opacity, valueThickness = valueArg.thickness, value = valueArg.value, valueRest = _objectWithoutPropertiesLoose(valueArg, ["color", "label", "onHover", "opacity", "thickness", "value"]); var key = "p-" + index; // Math.min/max are to handle negative values var bottom = value.length === 2 ? Math.min(Math.max(0, bounds[1][0]), value[1]) : Math.min(value[1], value[2]); var top = value.length === 2 ? Math.max(Math.min(0, bounds[1][1]), value[1]) : Math.max(value[1], value[2]); var d = "M " + valueToCoordinate(value[0], bottom).join(',') + (" L " + valueToCoordinate(value[0], top).join(',')); var hoverProps; if (valueOnHover) { hoverProps = { onMouseOver: function onMouseOver() { return valueOnHover(true); }, onMouseLeave: function onMouseLeave() { return valueOnHover(false); } }; } var clickProps; if (onClick) { clickProps = { onClick: onClick }; } return /*#__PURE__*/_react["default"].createElement("g", { key: key, fill: "none", stroke: valueColor ? (0, _utils.normalizeColor)(valueColor, theme) : undefined, strokeWidth: valueThickness ? (0, _utils.parseMetricToNum)(theme.global.edgeSize[valueThickness] || valueThickness) : undefined, opacity: valueOpacity && theme.global.opacity[valueOpacity] || valueOpacity }, /*#__PURE__*/_react["default"].createElement("title", null, label), /*#__PURE__*/_react["default"].createElement("path", _extends({ d: d }, hoverProps, clickProps, valueRest, { strokeDasharray: strokeDasharray }))); }); }; var renderLine = function renderLine() { var d = ''; var d2 = ''; (values || []).filter(function (_ref3) { var value = _ref3.value; return value[1] !== undefined; }).forEach(function (_ref4) { var value = _ref4.value; d += (d ? ' L' : 'M') + " " + valueToCoordinate(value[0], value[1]).join(','); if (value[2] !== undefined) { d2 += (d2 ? ' L' : 'M') + " " + valueToCoordinate(value[0], value[2]).join(','); } }); var hoverProps; if (onHover) { hoverProps = { onMouseOver: function onMouseOver() { return onHover(true); }, onMouseLeave: function onMouseLeave() { return onHover(false); } }; } var clickProps; if (onClick) { clickProps = { onClick: onClick }; } return /*#__PURE__*/_react["default"].createElement("g", { fill: "none" }, /*#__PURE__*/_react["default"].createElement("path", _extends({ d: d }, hoverProps, clickProps, { strokeDasharray: strokeDasharray })), d2 && /*#__PURE__*/_react["default"].createElement("path", _extends({ d: d2 }, hoverProps, clickProps, { strokeDasharray: strokeDasharray }))); }; var renderArea = function renderArea() { var d = ''; (values || []).filter(function (_ref5) { var value = _ref5.value; return value[1] !== undefined; }).forEach(function (_ref6, index) { var value = _ref6.value; d += (!index ? 'M' : ' L') + " " + valueToCoordinate(value[0], value[value.length === 2 ? 1 : 2]).join(','); }); (values || []).reverse().filter(function (_ref7) { var value = _ref7.value; return value[1] !== undefined; }).forEach(function (_ref8) { var value = _ref8.value; d += " L " + valueToCoordinate(value[0], // Math.max() is to account for value[1] being negative value.length === 2 ? Math.max(0, bounds[1][0]) : value[1]).join(','); }); if (d.length > 0) { d += ' Z'; } var hoverProps; if (onHover) { hoverProps = { onMouseOver: function onMouseOver() { return onHover(true); }, onMouseLeave: function onMouseLeave() { return onHover(false); } }; } var clickProps; if (onClick) { clickProps = { onClick: onClick }; } return /*#__PURE__*/_react["default"].createElement("g", null, /*#__PURE__*/_react["default"].createElement("path", _extends({ d: d }, hoverProps, clickProps))); }; var renderPoints = function renderPoints() { return (values || []).filter(function (_ref9) { var value = _ref9.value; return value[1] !== undefined; }).map(function (valueArg, index) { var valueColor = valueArg.color, label = valueArg.label, valueOnHover = valueArg.onHover, valueOpacity = valueArg.opacity, valueThickness = valueArg.thickness, value = valueArg.value, valueRest = _objectWithoutPropertiesLoose(valueArg, ["color", "label", "onHover", "opacity", "thickness", "value"]); var key = "p-" + index; var hoverProps; if (valueOnHover) { hoverProps = { onMouseOver: function onMouseOver() { return valueOnHover(true); }, onMouseLeave: function onMouseLeave() { return valueOnHover(false); } }; } var clickProps; if (onClick) { clickProps = { onClick: onClick }; } var width = valueThickness ? (0, _utils.parseMetricToNum)(theme.global.edgeSize[valueThickness] || valueThickness) : strokeWidth; var renderPoint = function renderPoint(valueX, valueY) { var props = _extends({}, hoverProps, clickProps, valueRest); var _valueToCoordinate = valueToCoordinate(valueX, valueY), cx = _valueToCoordinate[0], cy = _valueToCoordinate[1]; var off = width / 2; if (point === 'circle' || !point && round) return /*#__PURE__*/_react["default"].createElement("circle", _extends({ cx: cx, cy: cy, r: off }, props)); var d; if (point === 'diamond') d = "M " + cx + " " + (cy - off) + " L " + (cx + off) + " " + cy + " L " + cx + " " + (cy + off) + " L " + (cx - off) + " " + cy + " Z";else if (point === 'star') { var off1 = off / 3; var off2 = off1 * 2; d = "M " + cx + " " + (cy - off) + " L " + (cx - off2) + " " + (cy + off) + " L " + (cx + off) + " " + (cy - off1) + " L " + (cx - off) + " " + (cy - off1) + " L " + (cx + off2) + " " + (cy + off) + " Z"; } else if (point === 'triangle') d = "M " + cx + " " + (cy - off) + " L " + (cx + off) + " " + (cy + off) + " L " + (cx - off) + " " + (cy + off) + " Z";else if (point === 'triangleDown') d = "M " + (cx - off) + " " + (cy - off) + " L " + (cx + off) + " " + (cy - off) + " L " + cx + " " + (cy + off) + " Z"; // square else d = "M " + (cx - off) + " " + (cy - off) + " L " + (cx + off) + " " + (cy - off) + " L " + (cx + off) + " " + (cy + off) + " L " + (cx - off) + " " + (cy + off) + " Z"; return /*#__PURE__*/_react["default"].createElement("path", { d: d }); }; return /*#__PURE__*/_react["default"].createElement("g", { key: key, stroke: "none", fill: valueColor ? (0, _utils.normalizeColor)(valueColor, theme) : undefined, opacity: valueOpacity && theme.global.opacity[valueOpacity] || valueOpacity }, /*#__PURE__*/_react["default"].createElement("title", null, label), renderPoint(value[0], value[1]), value[2] !== undefined && renderPoint(value[0], value[2])); }); }; var contents; if (type === 'bar') { contents = renderBars(); } else if (type === 'line') { contents = renderLine(); } else if (type === 'area') { contents = renderArea(); } else if (type === 'point') { contents = renderPoints(); } var viewBox = viewBounds.join(' '); var colorName; if (!useGradient) { if (color && color.color) colorName = color.color;else if (color) colorName = color;else if (theme.chart && theme.chart.color) colorName = theme.chart.color; } var opacity = propsOpacity || color && color.opacity ? theme.global.opacity[propsOpacity || color.opacity] || propsOpacity || color.opacity : undefined; var stroke; if (type !== 'point') { if (useGradient) stroke = gradientMaskColor;else stroke = (0, _utils.normalizeColor)(colorName, theme); } else stroke = 'none'; var fill; if (type === 'point' || type === 'area') { if (useGradient) fill = gradientMaskColor;else fill = (0, _utils.normalizeColor)(colorName, theme); } else fill = 'none'; var drawing = /*#__PURE__*/_react["default"].createElement("g", { stroke: stroke, strokeWidth: type !== 'point' ? strokeWidth : undefined, fill: fill, strokeLinecap: round ? 'round' : 'butt', strokeLinejoin: round ? 'round' : 'miter', opacity: opacity }, contents); var defs; var gradientRect; if (useGradient && size[1]) { var uniqueGradientId = color.map(function (element) { return element.color; }).join('-'); var gradientId = uniqueGradientId + "-" + id + "-gradient"; var maskId = uniqueGradientId + "-" + id + "-mask"; defs = /*#__PURE__*/_react["default"].createElement("defs", null, /*#__PURE__*/_react["default"].createElement("linearGradient", { id: gradientId, x1: 0, y1: 0, x2: 0, y2: 1 }, color.sort(function (c1, c2) { return c2.value - c1.value; }).map(function (_ref10) { var value = _ref10.value, gradientColor = _ref10.color; return /*#__PURE__*/_react["default"].createElement("stop", { key: value, offset: // TODO: (size[1] - (value - bounds[1][0]) * scale[1]) / size[1], stopColor: (0, _utils.normalizeColor)(gradientColor, theme) }); })), /*#__PURE__*/_react["default"].createElement("mask", { id: maskId }, drawing)); gradientRect = /*#__PURE__*/_react["default"].createElement("rect", { x: viewBounds[0], y: viewBounds[1], width: viewBounds[2], height: viewBounds[3], fill: "url(#" + gradientId + ")", mask: "url(#" + maskId + ")" }); } return /*#__PURE__*/_react["default"].createElement(_StyledChart.StyledChart, _extends({ ref: containerRef, id: id, "aria-label": a11yTitle, viewBox: viewBox, preserveAspectRatio: "none", width: size === 'full' ? '100%' : size[0], height: size === 'full' ? '100%' : size[1], typeProp: type // prevent adding to DOM }, rest), defs, useGradient ? gradientRect : drawing); }); Chart.displayName = 'Chart'; var ChartDoc; if (process.env.NODE_ENV !== 'production') { ChartDoc = require('./doc').doc(Chart); // eslint-disable-line global-require } var ChartWrapper = ChartDoc || Chart; exports.Chart = ChartWrapper;