@dotconnor/grommet
Version:
focus on the essential experience
510 lines (424 loc) • 19.5 kB
JavaScript
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;
;