UNPKG

diagram-js

Version:

A toolbox for displaying and modifying diagrams on the web

202 lines (162 loc) 4.41 kB
import { getBBox } from '../../util/Elements'; var LOW_PRIORITY = 500; import { append as svgAppend, attr as svgAttr, create as svgCreate } from 'tiny-svg'; import { query as domQuery } from 'min-dom'; import { assign, forEach, isFunction } from 'min-dash'; var DEFAULT_PRIORITY = 1000; /** * @typedef {import('../../model/Types').Element} Element * * @typedef {import('./OutlineProvider').default} OutlineProvider * @typedef {import('../../core/EventBus').default} EventBus * @typedef {import('../../draw/Styles').default} Styles */ /** * @class * * A plugin that adds an outline to shapes and connections that may be activated and styled * via CSS classes. * * @param {EventBus} eventBus * @param {Styles} styles */ export default function Outline(eventBus, styles) { this._eventBus = eventBus; this.offset = 5; var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]); var self = this; /** * @param {SVGElement} gfx * * @return {SVGElement} outline */ function createOutline(gfx) { var outline = svgCreate('rect'); svgAttr(outline, assign({ x: 0, y: 0, rx: 4, width: 100, height: 100 }, OUTLINE_STYLE)); return outline; } // A low priortity is necessary, because outlines of labels have to be updated // after the label bounds have been updated in the renderer. eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY, function(event) { var element = event.element, gfx = event.gfx; var outline = domQuery('.djs-outline', gfx); if (!outline) { outline = self.getOutline(element) || createOutline(gfx); svgAppend(gfx, outline); } self.updateShapeOutline(outline, element); }); eventBus.on([ 'connection.added', 'connection.changed' ], function(event) { var element = event.element, gfx = event.gfx; var outline = domQuery('.djs-outline', gfx); if (!outline) { outline = createOutline(gfx); svgAppend(gfx, outline); } self.updateConnectionOutline(outline, element); }); } /** * Updates the outline of a shape respecting the dimension of the * element and an outline offset. * * @param {SVGElement} outline * @param {Element} element */ Outline.prototype.updateShapeOutline = function(outline, element) { var updated = false; var providers = this._getProviders(); if (providers.length) { forEach(providers, function(provider) { updated = updated || provider.updateOutline(element, outline); }); } if (!updated) { svgAttr(outline, { x: -this.offset, y: -this.offset, width: element.width + this.offset * 2, height: element.height + this.offset * 2 }); } }; /** * Updates the outline of a connection respecting the bounding box of * the connection and an outline offset. * Register an outline provider with the given priority. * * @param {SVGElement} outline * @param {Element} connection */ Outline.prototype.updateConnectionOutline = function(outline, connection) { var bbox = getBBox(connection); svgAttr(outline, { x: bbox.x - this.offset, y: bbox.y - this.offset, width: bbox.width + this.offset * 2, height: bbox.height + this.offset * 2 }); }; /** * Register an outline provider with the given priority. * * @param {number} priority * @param {OutlineProvider} provider */ Outline.prototype.registerProvider = function(priority, provider) { if (!provider) { provider = priority; priority = DEFAULT_PRIORITY; } this._eventBus.on('outline.getProviders', priority, function(event) { event.providers.push(provider); }); }; /** * Returns the registered outline providers. * * @returns {OutlineProvider[]} */ Outline.prototype._getProviders = function() { var event = this._eventBus.createEvent({ type: 'outline.getProviders', providers: [] }); this._eventBus.fire(event); return event.providers; }; /** * Returns the outline for an element. * * @param {Element} element */ Outline.prototype.getOutline = function(element) { var outline; var providers = this._getProviders(); forEach(providers, function(provider) { if (!isFunction(provider.getOutline)) { return; } outline = outline || provider.getOutline(element); }); return outline; }; Outline.$inject = [ 'eventBus', 'styles', 'elementRegistry' ];