| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- import {
- forEach,
- reduce
- } from 'min-dash';
- import {
- getChildren,
- getVisual
- } from '../util/GraphicsUtil';
- import { translate } from '../util/SvgTransformUtil';
- import { clear as domClear } from 'min-dom';
- import {
- append as svgAppend,
- attr as svgAttr,
- classes as svgClasses,
- create as svgCreate,
- remove as svgRemove
- } from 'tiny-svg';
- import {
- isFrameElement
- } from '../util/Elements';
- /**
- * A factory that creates graphical elements
- *
- * @param {EventBus} eventBus
- * @param {ElementRegistry} elementRegistry
- */
- export default function GraphicsFactory(eventBus, elementRegistry) {
- this._eventBus = eventBus;
- this._elementRegistry = elementRegistry;
- }
- GraphicsFactory.$inject = [ 'eventBus' , 'elementRegistry' ];
- GraphicsFactory.prototype._getChildrenContainer = function(element) {
- var gfx = this._elementRegistry.getGraphics(element);
- var childrenGfx;
- // root element
- if (!element.parent) {
- childrenGfx = gfx;
- } else {
- childrenGfx = getChildren(gfx);
- if (!childrenGfx) {
- childrenGfx = svgCreate('g');
- svgClasses(childrenGfx).add('djs-children');
- svgAppend(gfx.parentNode, childrenGfx);
- }
- }
- return childrenGfx;
- };
- /**
- * Clears the graphical representation of the element and returns the
- * cleared visual (the <g class="djs-visual" /> element).
- */
- GraphicsFactory.prototype._clear = function(gfx) {
- var visual = getVisual(gfx);
- domClear(visual);
- return visual;
- };
- /**
- * Creates a gfx container for shapes and connections
- *
- * The layout is as follows:
- *
- * <g class="djs-group">
- *
- * <!-- the gfx -->
- * <g class="djs-element djs-(shape|connection|frame)">
- * <g class="djs-visual">
- * <!-- the renderer draws in here -->
- * </g>
- *
- * <!-- extensions (overlays, click box, ...) goes here
- * </g>
- *
- * <!-- the gfx child nodes -->
- * <g class="djs-children"></g>
- * </g>
- *
- * @param {string} type the type of the element, i.e. shape | connection
- * @param {SVGElement} [childrenGfx]
- * @param {number} [parentIndex] position to create container in parent
- * @param {boolean} [isFrame] is frame element
- *
- * @return {SVGElement}
- */
- GraphicsFactory.prototype._createContainer = function(
- type, childrenGfx, parentIndex, isFrame
- ) {
- var outerGfx = svgCreate('g');
- svgClasses(outerGfx).add('djs-group');
- // insert node at position
- if (typeof parentIndex !== 'undefined') {
- prependTo(outerGfx, childrenGfx, childrenGfx.childNodes[parentIndex]);
- } else {
- svgAppend(childrenGfx, outerGfx);
- }
- var gfx = svgCreate('g');
- svgClasses(gfx).add('djs-element');
- svgClasses(gfx).add('djs-' + type);
- if (isFrame) {
- svgClasses(gfx).add('djs-frame');
- }
- svgAppend(outerGfx, gfx);
- // create visual
- var visual = svgCreate('g');
- svgClasses(visual).add('djs-visual');
- svgAppend(gfx, visual);
- return gfx;
- };
- GraphicsFactory.prototype.create = function(type, element, parentIndex) {
- var childrenGfx = this._getChildrenContainer(element.parent);
- return this._createContainer(type, childrenGfx, parentIndex, isFrameElement(element));
- };
- GraphicsFactory.prototype.updateContainments = function(elements) {
- var self = this,
- elementRegistry = this._elementRegistry,
- parents;
- parents = reduce(elements, function(map, e) {
- if (e.parent) {
- map[e.parent.id] = e.parent;
- }
- return map;
- }, {});
- // update all parents of changed and reorganized their children
- // in the correct order (as indicated in our model)
- forEach(parents, function(parent) {
- var children = parent.children;
- if (!children) {
- return;
- }
- var childrenGfx = self._getChildrenContainer(parent);
- forEach(children.slice().reverse(), function(child) {
- var childGfx = elementRegistry.getGraphics(child);
- prependTo(childGfx.parentNode, childrenGfx);
- });
- });
- };
- GraphicsFactory.prototype.drawShape = function(visual, element) {
- var eventBus = this._eventBus;
- return eventBus.fire('render.shape', { gfx: visual, element: element });
- };
- GraphicsFactory.prototype.getShapePath = function(element) {
- var eventBus = this._eventBus;
- return eventBus.fire('render.getShapePath', element);
- };
- GraphicsFactory.prototype.drawConnection = function(visual, element) {
- var eventBus = this._eventBus;
- return eventBus.fire('render.connection', { gfx: visual, element: element });
- };
- GraphicsFactory.prototype.getConnectionPath = function(waypoints) {
- var eventBus = this._eventBus;
- return eventBus.fire('render.getConnectionPath', waypoints);
- };
- GraphicsFactory.prototype.update = function(type, element, gfx) {
- // do NOT update root element
- if (!element.parent) {
- return;
- }
- var visual = this._clear(gfx);
- // redraw
- if (type === 'shape') {
- this.drawShape(visual, element);
- // update positioning
- translate(gfx, element.x, element.y);
- } else
- if (type === 'connection') {
- this.drawConnection(visual, element);
- } else {
- throw new Error('unknown type: ' + type);
- }
- if (element.hidden) {
- svgAttr(gfx, 'display', 'none');
- } else {
- svgAttr(gfx, 'display', 'block');
- }
- };
- GraphicsFactory.prototype.remove = function(element) {
- var gfx = this._elementRegistry.getGraphics(element);
- // remove
- svgRemove(gfx.parentNode);
- };
- // helpers //////////
- function prependTo(newNode, parentNode, siblingNode) {
- var node = siblingNode || parentNode.firstChild;
- // do not prepend node to itself to prevent IE from crashing
- // https://github.com/bpmn-io/bpmn-js/issues/746
- if (newNode === node) {
- return;
- }
- parentNode.insertBefore(newNode, node);
- }
|