Skip to content

Commit

Permalink
feat: support outline providers
Browse files Browse the repository at this point in the history
  • Loading branch information
smbea authored and philippfromme committed Oct 30, 2023
1 parent 651f40c commit 2b01eca
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 47 deletions.
110 changes: 78 additions & 32 deletions lib/features/outline/Outline.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { getBBox } from '../../util/Elements';

var LOW_PRIORITY = 500;

import {
Expand All @@ -13,9 +11,13 @@ import {
} from 'min-dom';

import {
assign
assign,
forEach,
isFunction
} from 'min-dash';

var DEFAULT_PRIORITY = 1000;

/**
* @typedef {import('../../model/Types').Element} Element
*
Expand All @@ -34,25 +36,25 @@ import {
*/
export default function Outline(eventBus, styles) {

this.offset = 6;
this._eventBus = eventBus;

this.offset = 5;

var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]);

var self = this;

function createOutline(gfx, bounds) {
function createOutline(gfx, element) {
var outline = svgCreate('rect');

svgAttr(outline, assign({
x: 10,
y: 10,
x: - self.offset,
y: - self.offset,
rx: 4,
width: 100,
height: 100
width: element.width + self.offset * 2,
height: element.height + self.offset * 2
}, OUTLINE_STYLE));

svgAppend(gfx, outline);

return outline;
}

Expand All @@ -65,10 +67,12 @@ export default function Outline(eventBus, styles) {
var outline = domQuery('.djs-outline', gfx);

if (!outline) {
outline = createOutline(gfx, element);
}
outline = self.getOutline(element) || createOutline(gfx, element);
svgAppend(gfx, outline);

self.updateShapeOutline(outline, element);
} else {
self.updateShapeOutline(outline, element);
}
});

}
Expand All @@ -83,35 +87,77 @@ export default function Outline(eventBus, styles) {
*/
Outline.prototype.updateShapeOutline = function(outline, element) {

svgAttr(outline, {
x: -this.offset,
y: -this.offset,
width: element.width + this.offset * 2,
height: element.height + this.offset * 2
});
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
* @param {number} priority
* @param {OutlineProvider} provider
*/
Outline.prototype.updateConnectionOutline = function(outline, connection) {
Outline.prototype.registerProvider = function(priority, provider) {
if (!provider) {
provider = priority;
priority = DEFAULT_PRIORITY;
}

var bbox = getBBox(connection);
this._eventBus.on('outline.getProviders', priority, function(event) {
event.providers.push(provider);
});
};

svgAttr(outline, {
x: bbox.x - this.offset,
y: bbox.y - this.offset,
width: bbox.width + this.offset * 2,
height: bbox.height + this.offset * 2
/**
* 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' ];
34 changes: 34 additions & 0 deletions lib/features/outline/OutlineProvider.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {
attr as svgAttr,
create as svgCreate
} from 'tiny-svg';

import { Element } from '../../model/Types';

import OutlineProvider, { Outline } from './OutlineProvider';

export class FooOutlineProvider implements OutlineProvider {
getOutline(element: Element): Outline {
const outline = svgCreate('circle');

svgAttr(outline, {
cx: element.width / 2,
cy: element.height / 2,
r: 23
});

return outline;
}

updateOutline(element: Element, outline: Outline): boolean {
if (element.type === 'Foo') {
svgAttr(outline, {
cx: element.width / 2,
cy: element.height / 2,
r: 23
});
}

return false;
}
}
61 changes: 61 additions & 0 deletions lib/features/outline/OutlineProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Element } from '../../model/Types';

export type Outline = SVGSVGElement | SVGCircleElement | SVGRectElement;

/**
* An interface to be implemented by an outline provider.
*/
export default interface OutlineProvider {

/**
* Returns outline shape for given element.
*
* @example
*
* ```javascript
* getOutline(element) {
* if (element.type === 'Foo') {
* const outline = svgCreate('circle');
*
* svgAttr(outline, {
* cx: element.width / 2,
* cy: element.height / 2,
* r: 23
* });
*
* return outline;
* }
* }
* ```
*
* @param element
*/
getOutline: (element: Element) => Outline;

/**
* Updates outline shape based on element's current size. Returns true if
* update was handled by provider.
*
* @example
*
* ```javascript
* updateOutline(element, outline) {
* if (element.type === 'Foo') {
* svgAttr(outline, {
* cx: element.width / 2,
* cy: element.height / 2,
* r: 23
* });
* } else if (element.type === 'Bar') {
* return true;
* }
*
* return false;
* }
* ```
*
* @param element
* @param outline
*/
updateOutline: (element: Element, outline: Outline) => boolean;
}
Loading

0 comments on commit 2b01eca

Please sign in to comment.