From 0c4d04b7ce90cfb3840ae031e34b2311c1667075 Mon Sep 17 00:00:00 2001 From: Nico Rehwaldt Date: Thu, 19 May 2022 15:07:32 +0200 Subject: [PATCH] feat(selection): visually improve multi-selection mode * separate primary from secondary selection * hide bendpoint + segment draggers on multi-select --- assets/diagram-js.css | 29 ++++++++++----- lib/features/selection/SelectionVisuals.js | 10 ++++- .../selection/SelectionVisualsSpec.js | 37 ++++++++++++++++--- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/assets/diagram-js.css b/assets/diagram-js.css index ba617c2ca..b2d2b5847 100644 --- a/assets/diagram-js.css +++ b/assets/diagram-js.css @@ -15,6 +15,7 @@ --color-blue-205-100-45: hsl(205, 100%, 45%); --color-blue-205-100-45-opacity-30: hsla(205, 100%, 45%, 30%); --color-blue-205-100-50: hsl(205, 100%, 50%); + --color-blue-205-100-70: hsl(205, 100%, 75%); --color-blue-205-100-95: hsl(205, 100%, 95%); --color-green-150-86-44: hsl(150, 86%, 44%); @@ -40,6 +41,7 @@ --element-dragger-color: var(--color-blue-205-100-50); --element-hover-outline-fill-color: var(--color-blue-205-100-45); --element-selected-outline-stroke-color: var(--color-blue-205-100-50); + --element-selected-outline-secondary-stroke-color: var(--color-blue-205-100-70); --lasso-fill-color: var(--color-black-opacity-05); --lasso-stroke-color: var(--color-black); @@ -90,17 +92,29 @@ * outline styles */ -.djs-outline { +.djs-outline, +.djs-selection-outline { fill: none; + shape-rendering: geometricPrecision; + stroke-width: 2px; +} + +.djs-outline { visibility: hidden; } +.djs-selection-outline { + stroke: var(--element-selected-outline-stroke-color); +} + .djs-element.selected .djs-outline { visibility: visible; - shape-rendering: geometricPrecision; stroke: var(--element-selected-outline-stroke-color); - stroke-width: 1px; +} + +.djs-multi-select .djs-element.selected .djs-outline { + stroke: var(--element-selected-outline-secondary-stroke-color); } .djs-shape.connect-ok .djs-visual > :nth-child(1) { @@ -667,6 +681,8 @@ marker.djs-dragger tspan { .djs-updating .djs-context-pad, .djs-updating .djs-outline, .djs-updating .djs-bendpoint, +.djs-multi-select .djs-bendpoint, +.djs-multi-select .djs-segment-dragger, .connect-ok .djs-bendpoint, .connect-not-ok .djs-bendpoint, .drop-ok .djs-bendpoint, @@ -799,11 +815,4 @@ marker.djs-dragger tspan { .djs-element-hidden .djs-outline, .djs-label-hidden .djs-label { display: none !important; -} - -.djs-selection-outline { - shape-rendering: geometricPrecision; - stroke: var(--element-selected-outline-stroke-color); - stroke-dasharray: 1,1; - stroke-width: 1px; } \ No newline at end of file diff --git a/lib/features/selection/SelectionVisuals.js b/lib/features/selection/SelectionVisuals.js index f4a1aa6b5..6962e797b 100644 --- a/lib/features/selection/SelectionVisuals.js +++ b/lib/features/selection/SelectionVisuals.js @@ -100,7 +100,13 @@ SelectionVisuals.prototype._updateSelectionOutline = function(selection) { svgClear(layer); - if (selection.length <= 1) { + var enabled = selection.length > 1; + + var container = this._canvas.getContainer(); + + svgClasses(container)[enabled ? 'add' : 'remove']('djs-multi-select'); + + if (!enabled) { return; } @@ -109,7 +115,7 @@ SelectionVisuals.prototype._updateSelectionOutline = function(selection) { var rect = svgCreate('rect'); svgAttr(rect, assign({ - fill: 'none' + rx: 3 }, bBox)); svgClasses(rect).add('djs-selection-outline'); diff --git a/test/spec/features/selection/SelectionVisualsSpec.js b/test/spec/features/selection/SelectionVisualsSpec.js index c47ca9ba7..dbd0774f9 100755 --- a/test/spec/features/selection/SelectionVisualsSpec.js +++ b/test/spec/features/selection/SelectionVisualsSpec.js @@ -7,6 +7,7 @@ import selectionModule from 'lib/features/selection'; import modelingModule from 'lib/features/modeling'; import { + classes as domClasses, query as domQuery } from 'min-dom'; @@ -62,6 +63,7 @@ describe('features/selection/SelectionVisuals', function() { canvas.addConnection(connection); })); + describe('single element', function() { it('should show box on select', inject(function(selection, canvas) { @@ -76,6 +78,16 @@ describe('features/selection/SelectionVisuals', function() { expect(outline).to.exist; })); + + it('should not add djs-multi-select marker', inject(function(canvas) { + + // when + var element = canvas.getContainer(); + + // then + expect(domClasses(element).has('djs-multi-select')); + })); + }); @@ -94,12 +106,28 @@ describe('features/selection/SelectionVisuals', function() { })); - it('should show box', inject(function(selection) { + it('should show box', inject(function() { expect(outline).to.exist; })); - it('selection box should contain all selected elements', inject(function(selection) { + it('should add djs-multi-select marker', inject(function(selection, canvas) { + + // when + var element = canvas.getContainer(); + + // then + expect(domClasses(element).has('djs-multi-select')).to.be.true; + + // but when + selection.select(null); + + // then + expect(domClasses(element).has('djs-multi-select')).to.be.false; + })); + + + it('selection box should contain all selected elements', inject(function() { // then selectedShapes.forEach(function(shape) { @@ -110,11 +138,10 @@ describe('features/selection/SelectionVisuals', function() { expect(bbox.x + bbox.width).to.be.at.most(bounds.x + bounds.width); expect(bbox.y + bbox.height).to.be.at.most(bounds.y + bounds.height); }); - })); - it('selection box should react to element changes', inject(function(selection, modeling) { + it('selection box should react to element changes', inject(function(modeling) { // when modeling.resizeShape(shape2, resizeBounds(bounds, 'nw', { x: 10, y: 20 })); @@ -139,7 +166,7 @@ describe('features/selection/SelectionVisuals', function() { })); - it('selection box should react to undo/redo', inject(function(selection, modeling, commandStack) { + it('selection box should react to undo/redo', inject(function(modeling, commandStack) { // given modeling.resizeShape(shape2, resizeBounds(shape, 'nw', { x: 10, y: 20 }));