diagram-js
Version:
A toolbox for displaying and modifying diagrams on the web
202 lines (162 loc) • 4.41 kB
JavaScript
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' ];