UNPKG

sprotty

Version:

A next-gen framework for graphical views

187 lines 8.62 kB
"use strict"; /******************************************************************************** * Copyright (c) 2017-2018 TypeFox and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. * * This Source Code may also be made available under the following Secondary * Licenses when the conditions for such availability set forth in the Eclipse * Public License v. 2.0 are satisfied: GNU General Public License, version 2 * with the GNU Classpath Exception which is available at * https://www.gnu.org/software/classpath/license.html. * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ATTR_BBOX_ELEMENT = exports.HiddenBoundsUpdater = exports.BoundsData = void 0; const inversify_1 = require("inversify"); const actions_1 = require("sprotty-protocol/lib/actions"); const geometry_1 = require("sprotty-protocol/lib/utils/geometry"); const browser_1 = require("../../utils/browser"); const smodel_1 = require("../../base/model/smodel"); const types_1 = require("../../base/types"); const layout_1 = require("./layout"); const model_1 = require("./model"); class BoundsData { } exports.BoundsData = BoundsData; /** * Grabs the bounds from hidden SVG DOM elements, applies layouts and fires * ComputedBoundsActions. * * The actual bounds of an element can usually not be determined from the SModel * as they depend on the view implementation and CSS stylings. So the best way is * to grab them from a live (but hidden) SVG using getBBox(). * * If an element is Alignable, and the top-left corner of its bounding box is not * the origin, we also issue a realign with the ComputedBoundsAction. */ let HiddenBoundsUpdater = class HiddenBoundsUpdater { constructor() { this.element2boundsData = new Map; } decorate(vnode, element) { if ((0, model_1.isSizeable)(element) || (0, model_1.isLayoutContainer)(element)) { this.element2boundsData.set(element, { vnode: vnode, bounds: element.bounds, boundsChanged: false, alignmentChanged: false }); } if (element instanceof smodel_1.SModelRootImpl) { this.root = element; } return vnode; } postUpdate(cause) { if (cause === undefined || cause.kind !== actions_1.RequestBoundsAction.KIND) { return; } const request = cause; this.getBoundsFromDOM(); this.layouter.layout(this.element2boundsData); const resizes = []; const alignments = []; this.element2boundsData.forEach((boundsData, element) => { if (boundsData.boundsChanged && boundsData.bounds !== undefined) { const resize = { elementId: element.id, newSize: { width: boundsData.bounds.width, height: boundsData.bounds.height } }; // don't copy position if the element is layouted by the server if (element instanceof smodel_1.SChildElementImpl && (0, model_1.isLayoutContainer)(element.parent)) { resize.newPosition = { x: boundsData.bounds.x, y: boundsData.bounds.y, }; } resizes.push(resize); } if (boundsData.alignmentChanged && boundsData.alignment !== undefined) { alignments.push({ elementId: element.id, newAlignment: boundsData.alignment }); } }); const revision = (this.root !== undefined) ? this.root.revision : undefined; this.actionDispatcher.dispatch(actions_1.ComputedBoundsAction.create(resizes, { revision, alignments, requestId: request.requestId })); this.element2boundsData.clear(); } getBoundsFromDOM() { this.element2boundsData.forEach((boundsData, element) => { if (boundsData.bounds && (0, model_1.isSizeable)(element)) { const vnode = boundsData.vnode; if (vnode && vnode.elm) { const boundingBox = this.getBounds(vnode.elm, element); if ((0, model_1.isAlignable)(element) && !((0, geometry_1.almostEquals)(boundingBox.x, 0) && (0, geometry_1.almostEquals)(boundingBox.y, 0))) { boundsData.alignment = { x: -boundingBox.x, y: -boundingBox.y }; boundsData.alignmentChanged = true; } const newBounds = { x: element.bounds.x, y: element.bounds.y, width: boundingBox.width, height: boundingBox.height }; if (!((0, geometry_1.almostEquals)(newBounds.x, element.bounds.x) && (0, geometry_1.almostEquals)(newBounds.y, element.bounds.y) && (0, geometry_1.almostEquals)(newBounds.width, element.bounds.width) && (0, geometry_1.almostEquals)(newBounds.height, element.bounds.height))) { boundsData.bounds = newBounds; boundsData.boundsChanged = true; } } } }); } /** * Compute the bounds of the given DOM element. Override this method to customize how * the bounding box of a rendered view is determined. * * In case your Sprotty model element contains children that are rendered outside of * their parent, you can add the `ATTR_BBOX_ELEMENT` attribute to the SVG element * that shall be used to compute the bounding box. */ getBounds(elm, element) { if (!(0, browser_1.isSVGGraphicsElement)(elm)) { this.logger.error(this, 'Not an SVG element:', elm); return geometry_1.Bounds.EMPTY; } if (elm.tagName === 'g') { for (const child of Array.from(elm.children)) { if (child.getAttribute(exports.ATTR_BBOX_ELEMENT) !== null) { return this.getBounds(child, element); } } } const bounds = elm.getBBox(); return { x: bounds.x, y: bounds.y, width: bounds.width, height: bounds.height }; } }; exports.HiddenBoundsUpdater = HiddenBoundsUpdater; __decorate([ (0, inversify_1.inject)(types_1.TYPES.ILogger), __metadata("design:type", Object) ], HiddenBoundsUpdater.prototype, "logger", void 0); __decorate([ (0, inversify_1.inject)(types_1.TYPES.IActionDispatcher), __metadata("design:type", Object) ], HiddenBoundsUpdater.prototype, "actionDispatcher", void 0); __decorate([ (0, inversify_1.inject)(types_1.TYPES.Layouter), __metadata("design:type", layout_1.Layouter) ], HiddenBoundsUpdater.prototype, "layouter", void 0); exports.HiddenBoundsUpdater = HiddenBoundsUpdater = __decorate([ (0, inversify_1.injectable)() ], HiddenBoundsUpdater); /** * Attribute name identifying the SVG element that determines the bounding box of a rendered view. * This can be used when a view creates a group of which only a part should contribute to the * bounding box computed by `HiddenBoundsUpdater`. */ exports.ATTR_BBOX_ELEMENT = 'bboxElement'; //# sourceMappingURL=hidden-bounds-updater.js.map