"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _exportNames = { shapesForNodes: true, globalStateUpdater: true, crawlTree: true }; exports.shapesForNodes = exports.globalStateUpdater = exports.crawlTree = void 0; var _recompose = require("recompose"); var _workpad = require("../../state/selectors/workpad"); var _elements = require("../../state/actions/elements"); var _transient = require("../../state/actions/transient"); var _functional = require("../../lib/aeroelastic/functional"); var _layout_functions = require("../../lib/aeroelastic/layout_functions"); var _workpad2 = require("../../lib/workpad"); var _matrix = require("../../lib/aeroelastic/matrix"); var _positioning_utils = require("./positioning_utils"); Object.keys(_positioning_utils).forEach(function (key) { if (key === "default" || key === "__esModule") return; if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; if (key in exports && exports[key] === _positioning_utils[key]) return; Object.defineProperty(exports, key, { enumerable: true, get: function () { return _positioning_utils[key]; } }); }); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ const shapeToElement = shape => ({ left: shape.transformMatrix[12] - shape.a, top: shape.transformMatrix[13] - shape.b, width: shape.a * 2, height: shape.b * 2, angle: Math.round((0, _matrix.matrixToAngle)(shape.transformMatrix) * 180 / Math.PI), parent: shape.parent || null, type: shape.type === 'group' ? 'group' : 'element' }); const globalPositionUpdates = (setMultiplePositions, { shapes, gestureEnd }, unsortedElements) => { const ascending = (a, b) => a.id < b.id ? -1 : 1; const relevant = s => s.type !== 'annotation' && s.subtype !== 'adHocGroup'; const elements = unsortedElements.filter(relevant).sort(ascending); const repositionings = shapes.filter(relevant).sort(ascending).map((shape, i) => { const element = elements[i]; const elemPos = element && element.position; if (elemPos && gestureEnd) { // get existing position information from element const oldProps = { left: elemPos.left, top: elemPos.top, width: elemPos.width, height: elemPos.height, angle: Math.round(elemPos.angle), type: elemPos.type, parent: elemPos.parent || null }; // cast shape into element-like object to compare const newProps = shapeToElement(shape); if (1 / newProps.angle === -Infinity) { newProps.angle = 0; } // recompose.shallowEqual discerns between 0 and -0 return (0, _recompose.shallowEqual)(oldProps, newProps) ? null : { position: newProps, elementId: shape.id }; } }).filter(_functional.identity); return repositionings; }; const dedupe = (d, i, a) => a.findIndex(s => s.id === d.id) === i; const missingParentCheck = groups => { const idMap = (0, _functional.arrayToMap)(groups.map(g => g.id)); groups.forEach(g => { if (g.parent && !idMap[g.parent]) { g.parent = null; } }); }; const shapesForNodes = nodes => { // For a group, it's z-layer should be the same as the highest of it's children // So we cache every nodes layer in this array so when we get to a group // we can refer back to all of the elements and figure out the appropriate layer // for the group const nodeLayers = nodes.map(() => null); const getNodeLayer = nodeIndex => { if (nodeLayers[nodeIndex]) { return nodeLayers[nodeIndex]; } const node = nodes[nodeIndex]; const thisId = node.id; const childrenIndexesOfThisNode = nodes.map((n, i) => [n, i]).filter(([node]) => node.position.parent === thisId).map(([, index]) => index); if (childrenIndexesOfThisNode.length === 0) { nodeLayers[nodeIndex] = nodeIndex; } else { const layer = Math.max(...childrenIndexesOfThisNode.map(getNodeLayer)); nodeLayers[nodeIndex] = layer; } return nodeLayers[nodeIndex]; }; const rawShapes = nodes.map((node, index) => { const layer = getNodeLayer(index); return (0, _positioning_utils.elementToShape)(node, layer); }) // filtering to eliminate residual element of a possible group that had been deleted in Redux .filter((d, i, a) => !(0, _workpad2.isGroupId)(d.id) || a.find(s => s.parent === d.id)).filter(dedupe); missingParentCheck(rawShapes); const getLocalMatrix = (0, _layout_functions.getLocalTransformMatrix)(rawShapes); return rawShapes.map(s => ({ ...s, localTransformMatrix: getLocalMatrix(s) })); }; exports.shapesForNodes = shapesForNodes; const updateGlobalPositionsInRedux = (setMultiplePositions, scene, unsortedElements) => { const repositionings = globalPositionUpdates(setMultiplePositions, scene, unsortedElements); if (repositionings.length) { setMultiplePositions(repositionings); } }; const globalStateUpdater = (dispatch, globalState) => state => { const nextScene = state.currentScene; const page = (0, _workpad.getSelectedPage)(globalState); const elements = (0, _workpad.getNodes)(globalState, page); const shapes = nextScene.shapes; const persistableGroups = shapes.filter(s => s.subtype === 'persistentGroup').filter(dedupe); const persistedGroups = elements.filter(e => (0, _workpad2.isGroupId)(e.id)).filter(dedupe); persistableGroups.forEach(g => { if (!persistedGroups.find(p => { if (!p.id) { throw new Error('Element has no id'); } return p.id === g.id; })) { const partialElement = { id: g.id, filter: undefined, expression: 'shape fill="rgba(255,255,255,0)" | render', position: { ...shapeToElement(g) } }; dispatch((0, _elements.addElement)(page, partialElement)); } }); const elementsToRemove = persistedGroups.filter( // list elements for removal if they're not in the persistable set, or if there's no longer an associated element // the latter of which shouldn't happen, so it's belts and braces p => !persistableGroups.find(g => p.id === g.id) || !elements.find(e => e.position.parent === p.id)); updateGlobalPositionsInRedux(positions => dispatch((0, _elements.setMultiplePositions)(positions.map(p => ({ ...p, pageId: page })))), nextScene, elements); if (elementsToRemove.length) { // remove elements for groups that were ungrouped dispatch((0, _elements.removeElements)(elementsToRemove.map(e => e.id), page)); } // set the selected element on the global store, if one element is selected const selectedPrimaryShapes = nextScene.selectedPrimaryShapes; if (!(0, _recompose.shallowEqual)(selectedPrimaryShapes, globalState.transient.selectedToplevelNodes)) { dispatch((0, _transient.selectToplevelNodes)((0, _functional.flatten)(selectedPrimaryShapes.map(n => n.startsWith('group') && (shapes.find(s => s.id === n) || {}).subtype === 'adHocGroup' ? shapes.filter(s => s.type !== 'annotation' && s.parent === n).map(s => s.id) : [n])))); } }; exports.globalStateUpdater = globalStateUpdater; const crawlTree = shapes => shapeId => { const rec = shapeId => [shapeId, ...(0, _functional.flatten)(shapes.filter(s => s.position.parent === shapeId).map(s => rec(s.id)))]; return rec(shapeId); }; exports.crawlTree = crawlTree;