UNPKG

@dotconnor/grommet

Version:

focus on the essential experience

240 lines (200 loc) 8.93 kB
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; } import React, { forwardRef, useCallback, useContext, useEffect, useRef, useState } from 'react'; import { ThemeContext } from 'styled-components'; import { defaultProps } from '../../default-props'; import { normalizeColor, parseMetricToNum, useForwardedRef } from '../../utils'; import { StyledDiagram } from './StyledDiagram'; var computeMidPoint = function computeMidPoint(fromPoint, toPoint) { return [fromPoint[0] > toPoint[0] ? toPoint[0] + (fromPoint[0] - toPoint[0]) / 2 : fromPoint[0] + (toPoint[0] - fromPoint[0]) / 2, fromPoint[1] > toPoint[1] ? toPoint[1] + (fromPoint[1] - toPoint[1]) / 2 : fromPoint[1] + (toPoint[1] - fromPoint[1]) / 2]; }; var COMMANDS = { curved: function curved(fromPoint, toPoint, offset, anchor) { var midPoint = computeMidPoint(fromPoint, toPoint); var cmds = "M " + (fromPoint[0] + offset) + "," + (fromPoint[1] + offset) + " "; if (anchor === 'horizontal') { cmds += "Q " + (midPoint[0] + offset) + "," + (fromPoint[1] + offset) + " " + (midPoint[0] + offset + "," + (midPoint[1] + offset) + " "); } else { cmds += "Q " + (fromPoint[0] + offset) + "," + (midPoint[1] + offset) + " " + (midPoint[0] + offset + "," + (midPoint[1] + offset) + " "); } cmds += "T " + (toPoint[0] + offset) + "," + (toPoint[1] + offset); return cmds; }, direct: function direct(fromPoint, toPoint, offset) { return "M " + (fromPoint[0] + offset) + "," + (fromPoint[1] + offset) + " " + ("L " + (toPoint[0] + offset) + "," + (toPoint[1] + offset)); }, rectilinear: function rectilinear(fromPoint, toPoint, offset, anchor) { var midPoint = computeMidPoint(fromPoint, toPoint); var cmds = "M " + (fromPoint[0] + offset) + "," + (fromPoint[1] + offset) + " "; if (anchor === 'horizontal') { cmds += "L " + (midPoint[0] + offset) + "," + (fromPoint[1] + offset) + " " + ("L " + (midPoint[0] + offset) + "," + (toPoint[1] + offset) + " "); } else { cmds += "L " + (fromPoint[0] + offset) + "," + (midPoint[1] + offset) + " " + ("L " + (toPoint[0] + offset) + "," + (midPoint[1] + offset) + " "); } cmds += "L " + (toPoint[0] + offset) + "," + (toPoint[1] + offset); return cmds; } }; var findTarget = function findTarget(target) { if (typeof target === 'string') { return document.getElementById(target); } return target; }; var Diagram = /*#__PURE__*/forwardRef(function (_ref, ref) { var connections = _ref.connections, rest = _objectWithoutPropertiesLoose(_ref, ["connections"]); var theme = useContext(ThemeContext) || defaultProps.theme; var _useState = useState({ width: 0, height: 0 }), dimensions = _useState[0], setDimensions = _useState[1]; var _useState2 = useState(), connectionPoints = _useState2[0], setConnectionPoints = _useState2[1]; var svgRef = useForwardedRef(ref); useEffect(function () { setConnectionPoints(undefined); }, [connections]); var onResize = useCallback(function () { var svg = svgRef.current; if (svg) { var rect = svg.getBoundingClientRect(); if (rect.width !== dimensions.width || rect.height !== dimensions.height) { setDimensions({ width: rect.width, height: rect.height }); setConnectionPoints(undefined); } } }, [dimensions.width, dimensions.height, svgRef]); // Ref that stores resize handler var savedOnResize = useRef(); // Update resize ref value if onResize changes. // This allows our effect below to always get latest handler useEffect(function () { savedOnResize.current = onResize; }, [onResize]); useEffect(function () { var onResizeHandler = function onResizeHandler(event) { return savedOnResize.current(event); }; onResizeHandler(); window.addEventListener('resize', onResizeHandler); return function () { window.removeEventListener('resize', onResizeHandler); }; }, []); var placeConnections = useCallback(function () { var containerRect = svgRef.current.getBoundingClientRect(); var updatedConnectionPoints = connections.map(function (_ref2) { var anchor = _ref2.anchor, fromTarget = _ref2.fromTarget, toTarget = _ref2.toTarget; var points; var fromElement = findTarget(fromTarget); var toElement = findTarget(toTarget); if (!fromElement) { console.warn("Diagram cannot find " + fromTarget); } if (!toElement) { console.warn("Diagram cannot find " + toTarget); } if (fromElement && toElement) { var fromRect = fromElement.getBoundingClientRect(); var toRect = toElement.getBoundingClientRect(); // There is no x and y when unit testing. var fromPoint = [fromRect.left - containerRect.left || 0, fromRect.top - containerRect.top || 0]; var toPoint = [toRect.left - containerRect.left || 0, toRect.top - containerRect.top || 0]; if (anchor === 'vertical') { fromPoint[0] += fromRect.width / 2; toPoint[0] += toRect.width / 2; if (fromRect.top < toRect.top) { fromPoint[1] += fromRect.height; } else { toPoint[1] += toRect.height; } } else if (anchor === 'horizontal') { fromPoint[1] += fromRect.height / 2; toPoint[1] += toRect.height / 2; if (fromRect.left < toRect.left) { fromPoint[0] += fromRect.width; } else { toPoint[0] += toRect.width; } } else { // center fromPoint[0] += fromRect.width / 2; fromPoint[1] += fromRect.height / 2; toPoint[0] += toRect.width / 2; toPoint[1] += toRect.height / 2; } points = [fromPoint, toPoint]; } return points; }); setConnectionPoints(updatedConnectionPoints); }, [connections, svgRef]); useEffect(function () { if (!connectionPoints) { placeConnections(); } }, [connectionPoints, placeConnections]); var paths; if (connectionPoints) { paths = connections.map(function (_ref3, index) { var anchor = _ref3.anchor, color = _ref3.color, offset = _ref3.offset, round = _ref3.round, thickness = _ref3.thickness, type = _ref3.type, connectionRest = _objectWithoutPropertiesLoose(_ref3, ["anchor", "color", "offset", "round", "thickness", "type"]); var path; var cleanedRest = _extends({}, connectionRest); delete cleanedRest.fromTarget; delete cleanedRest.toTarget; var points = connectionPoints[index]; if (points) { var offsetWidth = offset ? parseMetricToNum(theme.global.edgeSize[offset]) : 0; var d = COMMANDS[type || 'curved'](points[0], points[1], offsetWidth, anchor); var strokeWidth = thickness ? parseMetricToNum(theme.global.edgeSize[thickness] || thickness) : 1; var colorName = color || theme.diagram.line && theme.diagram.line.color; if (!colorName) { var colors = Object.keys(theme.global.colors).filter(function (n) { return n.match(/^graph-[0-9]$/); }); colorName = colors[index % colors.length]; } path = /*#__PURE__*/React.createElement("path", _extends({ // eslint-disable-next-line react/no-array-index-key key: index }, cleanedRest, { stroke: normalizeColor(colorName, theme), strokeWidth: strokeWidth, strokeLinecap: round ? 'round' : 'butt', strokeLinejoin: round ? 'round' : 'miter', fill: "none", d: d })); } return path; }); } return /*#__PURE__*/React.createElement(StyledDiagram, _extends({ ref: svgRef, viewBox: "0 0 " + dimensions.width + " " + dimensions.height, preserveAspectRatio: "xMinYMin meet" }, rest), /*#__PURE__*/React.createElement("g", null, paths)); }); Diagram.displayName = 'Diagram'; Diagram.defaultProps = { connections: [] }; var DiagramDoc; if (process.env.NODE_ENV !== 'production') { // eslint-disable-next-line global-require DiagramDoc = require('./doc').doc(Diagram); } var DiagramWrapper = DiagramDoc || Diagram; export { DiagramWrapper as Diagram };