| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- import {
- forEach
- } from 'min-dash';
- import {
- append as svgAppend,
- attr as svgAttr,
- classes as svgClasses,
- clone as svgClone,
- create as svgCreate,
- remove as svgRemove
- } from 'tiny-svg';
- import { query as domQuery } from 'min-dom';
- import { getVisual } from '../../util/GraphicsUtil';
- var MARKER_TYPES = [
- 'marker-start',
- 'marker-mid',
- 'marker-end'
- ];
- var NODES_CAN_HAVE_MARKER = [
- 'circle',
- 'ellipse',
- 'line',
- 'path',
- 'polygon',
- 'polyline',
- 'path',
- 'rect'
- ];
- /**
- * Adds support for previews of moving/resizing elements.
- */
- export default function PreviewSupport(elementRegistry, eventBus, canvas, styles) {
- this._elementRegistry = elementRegistry;
- this._canvas = canvas;
- this._styles = styles;
- this._clonedMarkers = {};
- var self = this;
- eventBus.on('drag.cleanup', function() {
- forEach(self._clonedMarkers, function(clonedMarker) {
- svgRemove(clonedMarker);
- });
- self._clonedMarkers = {};
- });
- }
- PreviewSupport.$inject = [
- 'elementRegistry',
- 'eventBus',
- 'canvas',
- 'styles'
- ];
- /**
- * Returns graphics of an element.
- *
- * @param {djs.model.Base} element
- *
- * @return {SVGElement}
- */
- PreviewSupport.prototype.getGfx = function(element) {
- return this._elementRegistry.getGraphics(element);
- };
- /**
- * Adds a move preview of a given shape to a given svg group.
- *
- * @param {djs.model.Base} element
- * @param {SVGElement} group
- * @param {SVGElement} [gfx]
- *
- * @return {SVGElement} dragger
- */
- PreviewSupport.prototype.addDragger = function(element, group, gfx) {
- gfx = gfx || this.getGfx(element);
- var dragger = svgClone(gfx);
- var bbox = gfx.getBoundingClientRect();
- this._cloneMarkers(getVisual(dragger));
- svgAttr(dragger, this._styles.cls('djs-dragger', [], {
- x: bbox.top,
- y: bbox.left
- }));
- svgAppend(group, dragger);
- return dragger;
- };
- /**
- * Adds a resize preview of a given shape to a given svg group.
- *
- * @param {djs.model.Base} element
- * @param {SVGElement} group
- *
- * @return {SVGElement} frame
- */
- PreviewSupport.prototype.addFrame = function(shape, group) {
- var frame = svgCreate('rect', {
- class: 'djs-resize-overlay',
- width: shape.width,
- height: shape.height,
- x: shape.x,
- y: shape.y
- });
- svgAppend(group, frame);
- return frame;
- };
- /**
- * Clone all markers referenced by a node and its child nodes.
- *
- * @param {SVGElement} gfx
- */
- PreviewSupport.prototype._cloneMarkers = function(gfx) {
- var self = this;
- if (gfx.childNodes) {
- // TODO: use forEach once we drop PhantomJS
- for (var i = 0; i < gfx.childNodes.length; i++) {
- // recursively clone markers of child nodes
- self._cloneMarkers(gfx.childNodes[ i ]);
- }
- }
- if (!canHaveMarker(gfx)) {
- return;
- }
- MARKER_TYPES.forEach(function(markerType) {
- if (svgAttr(gfx, markerType)) {
- var marker = getMarker(gfx, markerType, self._canvas.getContainer());
- self._cloneMarker(gfx, marker, markerType);
- }
- });
- };
- /**
- * Clone marker referenced by an element.
- *
- * @param {SVGElement} gfx
- * @param {SVGElement} marker
- * @param {string} markerType
- */
- PreviewSupport.prototype._cloneMarker = function(gfx, marker, markerType) {
- var markerId = marker.id;
- var clonedMarker = this._clonedMarkers[ markerId ];
- if (!clonedMarker) {
- clonedMarker = svgClone(marker);
- var clonedMarkerId = markerId + '-clone';
- clonedMarker.id = clonedMarkerId;
- svgClasses(clonedMarker)
- .add('djs-dragger')
- .add('djs-dragger-marker');
- this._clonedMarkers[ markerId ] = clonedMarker;
- var defs = domQuery('defs', this._canvas._svg);
- if (!defs) {
- defs = svgCreate('defs');
- svgAppend(this._canvas._svg, defs);
- }
- svgAppend(defs, clonedMarker);
- }
- var reference = idToReference(this._clonedMarkers[ markerId ].id);
- svgAttr(gfx, markerType, reference);
- };
- // helpers //////////
- /**
- * Get marker of given type referenced by node.
- *
- * @param {Node} node
- * @param {string} markerType
- * @param {Node} [parentNode]
- *
- * @param {Node}
- */
- function getMarker(node, markerType, parentNode) {
- var id = referenceToId(svgAttr(node, markerType));
- return domQuery('marker#' + id, parentNode || document);
- }
- /**
- * Get ID of fragment within current document from its functional IRI reference.
- * References may use single or double quotes.
- *
- * @param {string} reference
- *
- * @returns {string}
- */
- function referenceToId(reference) {
- return reference.match(/url\(['"]?#([^'"]*)['"]?\)/)[1];
- }
- /**
- * Get functional IRI reference for given ID of fragment within current document.
- *
- * @param {string} id
- *
- * @returns {string}
- */
- function idToReference(id) {
- return 'url(#' + id + ')';
- }
- /**
- * Check wether node type can have marker attributes.
- *
- * @param {Node} node
- *
- * @returns {boolean}
- */
- function canHaveMarker(node) {
- return NODES_CAN_HAVE_MARKER.indexOf(node.nodeName) !== -1;
- }
|