UNPKG

gpml2pvjson

Version:
337 lines 25.4 kB
import { findIndex } from "lodash/fp"; import { getStartSideByOrientation } from "../geom-utils"; import { DEFAULT_STUB_LENGTH } from "./edge"; import { getOrientationOfHyperedgeStartPoint, getOrientationOfHyperedgeEndPoint, validateOrientation } from "./orientation"; /* import { Point, PvjsonEdge, AttachablePoint, , SegmentPoint } from "../gpml2pvjson"; //*/ const INDEX_TO_DIMENSION = ["x", "y"]; function getActiveOrientationIndexAndDimension(orientation) { const activeOrientationIndex = findIndex((orientationScalar) => orientationScalar !== 0, orientation); const activeOrientationDimension = INDEX_TO_DIMENSION[activeOrientationIndex]; const otherOrientationDimension = activeOrientationDimension === "x" ? "y" : "x"; return { activeOrientationIndex, activeOrientationDimension, otherOrientationDimension }; } /** * calculateAllPoints for edges of type Elbow and Curved * * PathVisio-Java does not always specify all the points needed to draw edges * of type Elbow and Curved. Unless the user drags one or more of the * waypoints, PathVisio-Java will only specify the first and last points, * leaving implicit one or more additional points that are required to draw * the edge. * * Kaavio requires that a PvjsonEdge specifies ALL the points required for * drawing the edge, so this function calculates any implicit points required * to unambiguously specify an edge and returns the full set of points * (implicit points are made explicit). * * @param explicitPoints {Array} * @param [sourceEntity] {Object} entity from which the EDGE emanates * (never an Anchor) * @param [targetEntity] {Object} entity into which the EDGE terminates * (never an Anchor) * @return {Array} Full set of points required to render the edge */ export function calculateAllPoints(explicitPoints, sourceEntity, targetEntity) { let firstPoint = explicitPoints[0]; let lastPoint = explicitPoints[explicitPoints.length - 1]; // NOTE: we need at least one of the first point or the last point to have a // valid orientation. If that's not the case already, we try setting it here, // based on other information available to us. if (!validateOrientation(firstPoint.orientation)) { if (firstPoint.hasOwnProperty("isAttachedTo")) { // It is correct to specify <PvjsonEdge> as the type for // sourceEntity/targetEntity when calculating the orientation of a point // attached to another edge below, because we get into there if neither // the first nor last point have a valid orientation. If a point is // attached to a SingleFreeNode, a Group or a GPML State, it would already // have a valid orientation calculated by this point, so the point must // be either attached to nothing or else attached to an edge. firstPoint.orientation = getOrientationOfHyperedgeStartPoint(sourceEntity, firstPoint, lastPoint); } else { firstPoint.orientation = [-1, 0]; } } if (!validateOrientation(lastPoint.orientation)) { if (lastPoint.hasOwnProperty("isAttachedTo")) { // It is correct to specify <PvjsonEdge> as the type for // sourceEntity/targetEntity when calculating the orientation of a point // attached to another edge below, because we get into there if neither // the first nor last point have a valid orientation. If a point is // attached to a SingleFreeNode, a Group or a GPML State, it would already // have a valid orientation calculated by this point, so the point must // be either attached to nothing or else attached to an edge. lastPoint.orientation = getOrientationOfHyperedgeEndPoint(targetEntity, lastPoint, firstPoint); } else { const { x: x0, y: y0 } = firstPoint; const { x: x1, y: y1 } = lastPoint; const firstSide = getStartSideByOrientation(firstPoint.orientation); if (firstSide === "left") { if (x0 >= x1 && x0 < x1 + DEFAULT_STUB_LENGTH) { lastPoint.orientation = [1, 0]; } else { lastPoint.orientation = [-1, 0]; } } else if (firstSide === "right") { if (x0 + DEFAULT_STUB_LENGTH <= x1) { lastPoint.orientation = [1, 0]; } else { lastPoint.orientation = [-1, 0]; } } else { lastPoint.orientation = [-1, 0]; } } } if (explicitPoints.length > 2) { return explicitPoints; } let startPoint; let endPoint; let endEntity; let pointOrderReversed; if (validateOrientation(firstPoint.orientation)) { pointOrderReversed = false; startPoint = firstPoint; endPoint = lastPoint; endEntity = targetEntity; } else if (validateOrientation(lastPoint.orientation)) { pointOrderReversed = true; startPoint = lastPoint; endPoint = firstPoint; endEntity = sourceEntity; } else { throw new Error(`Either first or last point (or both) should have a valid orientation by now in calculateAllPoints( ${JSON.stringify(explicitPoints)}, ${JSON.stringify(sourceEntity)}, ${JSON.stringify(targetEntity)} )`); } const startOrientation = startPoint.orientation; const endOrientation = endPoint.orientation; const vectorSumOrientation = [ Math.sign(endPoint.x - startPoint.x), Math.sign(endPoint.y - startPoint.y) ]; const { activeOrientationIndex: activeStartOrientationIndex, activeOrientationDimension: activeStartOrientationDimension, otherOrientationDimension: otherStartOrientationDimension } = getActiveOrientationIndexAndDimension(startOrientation); const { activeOrientationIndex: activeEndOrientationIndex, activeOrientationDimension: activeEndOrientationDimension, otherOrientationDimension: otherEndOrientationDimension } = getActiveOrientationIndexAndDimension(endOrientation); const pvjsonPoints = []; pvjsonPoints.push(startPoint); // Calculate intermediate data points, which are implicit. // Remember that this refers to the minimum number of points required to // define the path, so 3 points could mean this: // // -------------------*------------------- // | | // | | // * * // // or this: // * // | // | // -------------------*------------------- // | // | // * // // or several other possible configurations // NOTE: when an edge is connected to a SingleFreeNode or a Group (how about a State?), // PathVisio-Java will route the edge around the side from which the edge // emanates, if needed. // But when an edge is connected to another edge, PathVisio-Java // does not do any special re-routing for that connection. if (activeStartOrientationIndex === activeEndOrientationIndex) { // Start and end orientations are parallel, e.g., // starts at right and ends on either right or left side, or // starts on top and ends on either top or bottom side. const activeOrientationIndex = activeStartOrientationIndex; const activeOrientationDimension = activeStartOrientationDimension; const otherOrientationDimension = otherStartOrientationDimension; const otherOrientationDimensionDisplacement = endPoint[otherOrientationDimension] - startPoint[otherOrientationDimension]; if (startOrientation[activeOrientationIndex] === vectorSumOrientation[activeOrientationIndex]) { // we don't have to avoid the start side pvjsonPoints[1] = {}; pvjsonPoints[1][otherOrientationDimension] = startPoint[otherOrientationDimension] + otherOrientationDimensionDisplacement / 2; if (startOrientation[activeOrientationIndex] === endOrientation[activeOrientationIndex]) { // *--- // | // | // * // | // | // ---------------------* pvjsonPoints[1][activeOrientationDimension] = startPoint[activeOrientationDimension] + startOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH; } else { // *------------------------- // | // | // * // | // | // *--- pvjsonPoints[1][activeOrientationDimension] = endPoint[activeOrientationDimension] - endOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH; } } else { // must initially route around start side if (startOrientation[activeOrientationIndex] === endOrientation[activeOrientationIndex]) { // *--- // | // | // * // | // | // -----------*----------- // | // | // * // | // | // ---* pvjsonPoints[1] = {}; pvjsonPoints[1][activeOrientationDimension] = startPoint[activeOrientationDimension] + startOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH; pvjsonPoints[1][otherOrientationDimension] = startPoint[otherOrientationDimension] + otherOrientationDimensionDisplacement / 4; pvjsonPoints[2] = {}; pvjsonPoints[2][activeOrientationDimension] = (startPoint[activeOrientationDimension] + endPoint[activeOrientationDimension]) / 2; pvjsonPoints[2][otherOrientationDimension] = startPoint[otherOrientationDimension] + otherOrientationDimensionDisplacement / 2; pvjsonPoints[3] = {}; pvjsonPoints[3][activeOrientationDimension] = endPoint[activeOrientationDimension] - endOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH; pvjsonPoints[3][otherOrientationDimension] = startPoint[otherOrientationDimension] + (3 * otherOrientationDimensionDisplacement) / 4; } else { // *--- // | // | // * // | // | // *--------------------- pvjsonPoints[1] = {}; pvjsonPoints[1][activeOrientationDimension] = startPoint[activeOrientationDimension] + startOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH; pvjsonPoints[1][otherOrientationDimension] = startPoint[otherOrientationDimension] + otherOrientationDimensionDisplacement / 2; } } } else { // Start and end orientations are perpendicular if (startOrientation[activeStartOrientationIndex] === vectorSumOrientation[activeStartOrientationIndex] && endOrientation[activeEndOrientationIndex] === vectorSumOrientation[activeEndOrientationIndex]) { // * // | // | // | // | // | // ---------------------* // // Do nothing. } else { // ---* // | // | // | // * // * | // | | // | | // --------*-------- // // or *--- // | // | // | // * // * | // | | // | | // --------*-------- // // or // // ----* // | // | // * // | // | // ---*--- // | // | // * const otherStartOrientationDimensionDisplacement = endPoint[otherStartOrientationDimension] - endOrientation[activeEndOrientationIndex] * DEFAULT_STUB_LENGTH - startPoint[otherStartOrientationDimension]; pvjsonPoints[1] = {}; pvjsonPoints[1][activeStartOrientationDimension] = startPoint[activeStartOrientationDimension] + startOrientation[activeStartOrientationIndex] * DEFAULT_STUB_LENGTH; pvjsonPoints[1][otherStartOrientationDimension] = startPoint[otherStartOrientationDimension] + otherStartOrientationDimensionDisplacement / 2; pvjsonPoints[2] = {}; pvjsonPoints[2][activeEndOrientationDimension] = endPoint[activeEndOrientationDimension] - endOrientation[activeEndOrientationIndex] * DEFAULT_STUB_LENGTH; pvjsonPoints[2][otherEndOrientationDimension] = (pvjsonPoints[1][otherEndOrientationDimension] + endPoint[otherEndOrientationDimension]) / 2; } } pvjsonPoints.push(endPoint); return pointOrderReversed ? pvjsonPoints.reverse() : pvjsonPoints; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsY3VsYXRlQWxsUG9pbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VkZ2UvY2FsY3VsYXRlQWxsUG9pbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBUSxTQUFTLEVBQTRCLE1BQU0sV0FBVyxDQUFDO0FBQ3RFLE9BQU8sRUFNTCx5QkFBeUIsRUFJMUIsTUFBTSxlQUFlLENBQUM7QUFTdkIsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQzdDLE9BQU8sRUFDTCxtQ0FBbUMsRUFDbkMsaUNBQWlDLEVBQ2pDLG1CQUFtQixFQUNwQixNQUFNLGVBQWUsQ0FBQztBQUN2Qjs7Ozs7Ozs7SUFRSTtBQUVKLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7QUFFdEMsU0FBUyxxQ0FBcUMsQ0FBQyxXQUE2QjtJQUMxRSxNQUFNLHNCQUFzQixHQUFHLFNBQVMsQ0FDdEMsQ0FBQyxpQkFBeUIsRUFBRSxFQUFFLENBQUMsaUJBQWlCLEtBQUssQ0FBQyxFQUN0RCxXQUFXLENBQ1osQ0FBQztJQUNGLE1BQU0sMEJBQTBCLEdBQUcsa0JBQWtCLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUM5RSxNQUFNLHlCQUF5QixHQUM3QiwwQkFBMEIsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ2pELE9BQU87UUFDTCxzQkFBc0I7UUFDdEIsMEJBQTBCO1FBQzFCLHlCQUF5QjtLQUMxQixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRztBQUNILE1BQU0sVUFBVSxrQkFBa0IsQ0FDaEMsY0FBc0MsRUFDdEMsWUFBc0MsRUFDdEMsWUFBc0M7SUFFdEMsSUFBSSxVQUFVLEdBQUcsY0FBYyxDQUFDLENBQUMsQ0FBaUMsQ0FBQztJQUNuRSxJQUFJLFNBQVMsR0FBRyxjQUFjLENB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