Skip to content

Commit

Permalink
feat: custom selection outline
Browse files Browse the repository at this point in the history
Closes #799
  • Loading branch information
smbea committed Nov 3, 2023
1 parent 49b5ee6 commit 4e7b477
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/dmn-js-drd/src/Modeler.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import KeyboardMoveSelectionModule from 'diagram-js/lib/features/keyboard-move-s
import LabelEditingModule from './features/label-editing';
import ModelingModule from './features/modeling';
import MoveModule from 'diagram-js/lib/features/move';
import OutlineProvider from './features/outline';
import PaletteModule from './features/palette';
import ResizeModule from 'diagram-js/lib/features/resize';
import SnappingModule from './features/snapping';
Expand Down Expand Up @@ -131,6 +132,7 @@ Modeler.prototype._modelingModules = [
LabelEditingModule,
ModelingModule,
MoveModule,
OutlineProvider,
PaletteModule,
ResizeModule,
SnappingModule
Expand Down
125 changes: 125 additions & 0 deletions packages/dmn-js-drd/src/features/outline/OutlineProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { assign } from 'min-dash';

import {
attr as svgAttr,
create as svgCreate
} from 'tiny-svg';

import {
is,
isAny
} from 'dmn-js-shared/lib/util/ModelUtil';

import {
BUSINESS_KNOWLEDGE_MODEL_OUTLINE_PATH,
KNOWLEDGE_SOURCE_OUTLINE_PATH,
BUSINESS_KNOWLEDGE_MODEL_STANDARD_SIZE,
KNOWLEDGE_SOURCE_STANDARD_SIZE,
createPath
} from './OutlineUtil';

const DEFAULT_OFFSET = 5;

/**
* DMN-specific outline provider.
*
* @implements {BaseOutlineProvider}
*
* @param {Outline} outline
* @param {Styles} styles
*/
export default function OutlineProvider(outline, styles) {

this._styles = styles;

outline.registerProvider(this);
}

OutlineProvider.$inject = [
'outline',
'styles'
];

/**
* Returns outline for a given element.
*
* @param {Element} element
*
* @return {Outline}
*/
OutlineProvider.prototype.getOutline = function(element) {

const OUTLINE_STYLE = this._styles.cls('djs-outline', [ 'no-fill' ]);

var outline;

if (is(element, 'dmn:InputData')) {
outline = svgCreate('rect');

svgAttr(outline, assign({
x: -DEFAULT_OFFSET,
y: -DEFAULT_OFFSET,
rx: 27,
width: element.width + DEFAULT_OFFSET * 2,
height: element.height + DEFAULT_OFFSET * 2,
}, OUTLINE_STYLE));

} else if (
is(element, 'dmn:BusinessKnowledgeModel')
&& isStandardSize(element, 'dmn:BusinessKnowledgeModel')
) {
outline = createPath(
BUSINESS_KNOWLEDGE_MODEL_OUTLINE_PATH,
{ x: -6, y:-6 },
OUTLINE_STYLE
);

} else if (
is(element, 'dmn:KnowledgeSource')
&& isStandardSize(element, 'dmn:KnowledgeSource')) {
outline = createPath(
KNOWLEDGE_SOURCE_OUTLINE_PATH,
{ x: -6, y:-1.5 },
OUTLINE_STYLE
);
}

return outline;
};

/**
* Updates the outline for a given element.
* Returns true if the update for the given element was handled by this provider.
*
* @param {Element} element
* @param {Outline} outline
* @returns {boolean}
*/
OutlineProvider.prototype.updateOutline = function(element) {

if (isAny(element, [
'dmn:InputData',
'dmn:BusinessKnowledgeModel',
'dmn:KnowledgeSource'
])) {
return true;
}

return false;
};


// helpers //////////

function isStandardSize(element, type) {
var standardSize;

if (type === 'dmn:BusinessKnowledgeModel') {
standardSize = BUSINESS_KNOWLEDGE_MODEL_STANDARD_SIZE;
} else if (type === 'dmn:KnowledgeSource') {
standardSize = KNOWLEDGE_SOURCE_STANDARD_SIZE;
}

return element.width === standardSize.width
&& element.height === standardSize.height;
}
50 changes: 50 additions & 0 deletions packages/dmn-js-drd/src/features/outline/OutlineUtil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
create as svgCreate
} from 'tiny-svg';

export const BUSINESS_KNOWLEDGE_MODEL_OUTLINE_PATH = `
M2.45221 16.0068L18.7175 1.74436L18.0615 0.996331L18.7175 1.74436C19.2646 1.26455 19.9676
1 20.6953 1H140.926C142.583 1 143.926 2.34295 143.926 3.99967L143.93 37.5457C143.93
38.3668 143.593 39.152 142.999 39.7183L143.689 40.4424L142.999 39.7183L127.299
54.6723C126.741 55.2036 126 55.5 125.23 55.5H4.53787C2.88599 55.5 1.54491 54.1646 1.5379
52.5127L1.43066 27.229L1.43065 27.2248L1.4301 18.2626C1.43005
17.3986 1.80255 16.5765 2.45221 16.0068Z
`;


export const KNOWLEDGE_SOURCE_OUTLINE_PATH = `
M1.79494 63.0032L1.2941 63.6423L1.79493 63.0032C1.71778 62.9427 1.6428 62.8741 1.57288
62.8L1.01736 63.3241L1.57288 62.8C1.20495 62.41 1 61.8941 1 61.3579V2.65067C1 1.74066
1.73867 1.00345 2.64868 1.00526L108.006 1.2145C109.66 1.21778 111 2.55996 111
4.21449V21.7015V61.6762C111 63.3188 109.679 64.656 108.037 64.676L107.06 64.6879C106.66
64.6927 106.26 64.6165 105.89 64.4652C105.04 64.1176 104.222 63.78 103.43
63.4531C93.4866 59.3517 87.6891 56.9603 76.3991 58.1057C71.7035 58.5821 66.8747 60.74
61.5721 63.1744C61.3243 63.2881 61.0753 63.4026 60.825 63.5177C55.6712 65.8868 49.9696
68.5077 43.2365 70.3468C31.101 73.6617 15.2135 73.5179 1.79494 63.0032Z
`;

/**
* @type {Dimensions}
*/
export const BUSINESS_KNOWLEDGE_MODEL_STANDARD_SIZE = { width: 135, height: 46 };

/**
* @type {Dimensions}
*/
export const KNOWLEDGE_SOURCE_STANDARD_SIZE = { width: 100, height: 63 };

/**
* Create a path element with given attributes.
* @param {string} path
* @param {Object} attrs
* @param {Object} OUTLINE_STYLE
* @return {SVGElement}
*/
export function createPath(path, attrs, OUTLINE_STYLE) {
return svgCreate('path', {
d: path,
strokeWidth: 2,
transform: `translate(${attrs.x}, ${attrs.y})`,
...OUTLINE_STYLE
});
}
10 changes: 10 additions & 0 deletions packages/dmn-js-drd/src/features/outline/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Outline from 'diagram-js/lib/features/outline';
import OutlineProvider from './OutlineProvider';

export default {
__depends__: [
Outline
],
__init__: [ 'outlineProvider' ],
outlineProvider: [ 'type', OutlineProvider ]
};
32 changes: 32 additions & 0 deletions packages/dmn-js-drd/test/spec/features/outline/OutlineProvider.dmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/" xmlns:dmndi="https://www.omg.org/spec/DMN/20191111/DMNDI/" xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_11grvik" name="DRD" namespace="http://camunda.org/schema/1.0/dmn" exporter="Camunda Modeler" exporterVersion="5.15.0" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="8.2.0">
<decision id="Decision" name="Decision 1">
<decisionTable id="DecisionTable_16u0nds">
<input id="Input_1">
<inputExpression id="InputExpression_1" typeRef="string">
<text></text>
</inputExpression>
</input>
<output id="Output_1" typeRef="string" />
</decisionTable>
</decision>
<inputData id="InputData" />
<knowledgeSource id="KnowledgeSource" />
<businessKnowledgeModel id="BusinessKnowledgeModel" />
<dmndi:DMNDI>
<dmndi:DMNDiagram>
<dmndi:DMNShape dmnElementRef="Decision">
<dc:Bounds height="80" width="180" x="160" y="100" />
</dmndi:DMNShape>
<dmndi:DMNShape id="DMNShape_06ii2yj" dmnElementRef="InputData">
<dc:Bounds height="45" width="125" x="388" y="108" />
</dmndi:DMNShape>
<dmndi:DMNShape id="DMNShape_1toe7qd" dmnElementRef="KnowledgeSource">
<dc:Bounds height="63" width="100" x="190" y="239" />
</dmndi:DMNShape>
<dmndi:DMNShape id="DMNShape_1gqa9oy" dmnElementRef="BusinessKnowledgeModel">
<dc:Bounds height="46" width="135" x="384" y="248" />
</dmndi:DMNShape>
</dmndi:DMNDiagram>
</dmndi:DMNDI>
</definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
bootstrapModeler,
inject
} from 'test/TestHelper';

import coreModule from 'src/core';
import modelingModule from 'src/features/modeling';
import outlineProviderModule from 'src/features/outline';

import diagramXml from './OutlineProvider.dmn';

import {
KNOWLEDGE_SOURCE_OUTLINE_PATH,
BUSINESS_KNOWLEDGE_MODEL_OUTLINE_PATH
} from 'src/features/outline/OutlineUtil';


describe('features/outline - outline provider', function() {
var testModules = [
coreModule,
modelingModule,
outlineProviderModule
];


beforeEach(bootstrapModeler(diagramXml, { modules: testModules }));

describe('should provide outline for', function() {

it('input data', inject(function(elementRegistry, outline) {

// given
var inputData = elementRegistry.get('InputData');

// when
var outlineShape = outline.getOutline(inputData);

// then
expect(outlineShape).to.exist;
expect(outlineShape.tagName).to.eql('rect');
}));


it('knowledge source', inject(function(elementRegistry, outline) {

// given
var knowledgeSource = elementRegistry.get('KnowledgeSource');

// when
var outlineShape = outline.getOutline(knowledgeSource);

// then
expect(outlineShape).to.exist;
expect(outlineShape.tagName).to.eql('path');
expect(outlineShape.getAttribute('d')).to.eql(KNOWLEDGE_SOURCE_OUTLINE_PATH);
}));


it('business knowledge model', inject(function(elementRegistry, outline) {

// given
var businessKnowledgeModel = elementRegistry.get('BusinessKnowledgeModel');

// when
var outlineShape = outline.getOutline(businessKnowledgeModel);

// then
expect(outlineShape).to.exist;
expect(outlineShape.tagName).to.eql('path');
expect(outlineShape.getAttribute('d'))
.to.eql(BUSINESS_KNOWLEDGE_MODEL_OUTLINE_PATH);
}));

});

});

0 comments on commit 4e7b477

Please sign in to comment.