Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions lib/Minimap.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ export default function Minimap(
this._elementRegistry = elementRegistry;
this._eventBus = eventBus;
this._injector = injector;
this._config = config || {};
this._updateTimeout = null;
this._firstTimeoutStart = null;

this._state = {
isOpen: undefined,
Expand All @@ -73,7 +76,7 @@ export default function Minimap(

this._init();

this.toggle((config && config.open) || false);
this.toggle(this._config.open || false);

function centerViewbox(point) {

Expand Down Expand Up @@ -298,7 +301,7 @@ export default function Minimap(

self._addElement(element);

self._update();
self._debouncedUpdate();
});

// remove shape on shape/connection removed
Expand All @@ -307,7 +310,7 @@ export default function Minimap(

self._removeElement(element);

self._update();
self._debouncedUpdate();
});

// update on elements changed
Expand All @@ -318,7 +321,7 @@ export default function Minimap(
self._updateElement(element);
});

self._update();
self._debouncedUpdate();
});

// update on element ID update
Expand Down Expand Up @@ -435,7 +438,52 @@ Minimap.prototype._init = function() {
this._parent.appendChild(overlay);
};

Minimap.prototype._debouncedUpdate = function() {

// ignore updates if closed
if (!this.isOpen()) {
return;
}

const {
debounceDelay = 100,
debounceSkipDelay = 2000
} = this._config;

const now = Date.now();

// if we've been debouncing for a while already, force update
if (this._firstTimeoutStart && now - this._firstTimeoutStart >= debounceSkipDelay) {
return this._update();
}

// clear previous timeout
if (this._updateTimeout) {
clearTimeout(this._updateTimeout);
}

// fire debounced update
this._firstTimeoutStart = this._firstTimeoutStart || now;
this._updateTimeout = setTimeout(() => {
this._update();
}, debounceDelay);
};

Minimap.prototype._update = function() {

// ignore updates if closed
if (!this.isOpen()) {
return;
}

// if update was forced, clear any timeouts
if (this._updateTimeout) {
clearTimeout(this._updateTimeout);
this._updateTimeout = null;
}

this._firstTimeoutStart = null;

var viewbox = this._canvas.viewbox(),
innerViewbox = viewbox.inner,
outerViewbox = viewbox.outer;
Expand Down Expand Up @@ -536,6 +584,7 @@ Minimap.prototype.open = function() {

domAttr(this._toggle, 'title', translate('Close minimap'));

// open forces an update to ensure a viewbox is set and current
this._update();

this._eventBus.fire('minimap.toggle', { open: true });
Expand Down
91 changes: 91 additions & 0 deletions test/spec/MinimapSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,97 @@ describe('minimap', function() {
expectMinimapShapeToExist('child');
}));


// only use in isolation performance testing, this isn't a proper test and shouldn't run on CI
it.skip('performance test', inject(function(canvas, modeling, elementFactory, minimap) {

const GRID_MATRIX = [
[ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,0,0,0,0,2,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,1,1,1,1,1,0,3,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,1,4,4,1,1,2,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,1,4,4,1,0,2,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,1,4,4,1,0,2,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,1,3,2,1,1,3,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,0,0,0,0,2,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,1,1,1,0,1,3,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,1,4,4,1,0,2,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,1,4,4,2,0,1,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,1,4,4,2,0,1,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,1,4,4,2,1,1,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,1,1,2,2,1,0,2,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,0,0,0,0,1,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,3,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,0,0,0,0,0,2,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,1,1,1,1,1,1,2,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,2,0,0,0,0,0,0,2,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,3,2,2,2,2,2,2,3,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 ],
[ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 ]
];

const root = canvas.getRootElement();
const CELL = 40;
const GAP = 4;
const CHUNK = 150;

const tasks = [];

GRID_MATRIX.forEach((row, rIdx) => {
row.forEach((layers, cIdx) => {
for (let l = 0; l < layers; l++) {
const shrink = l * GAP;
const size = CELL - shrink * 2;
if (size <= 4) continue;
tasks.push({
id: `grid_${rIdx}_${cIdx}_${l}`,
x: cIdx * CELL + shrink,
y: rIdx * CELL + shrink,
width: size,
height: size
});
}
});
});

let index = 0;

function processChunk() {
const end = Math.min(index + CHUNK, tasks.length);

for (; index < end; index++) {
const t = tasks[index];
const shape = elementFactory.createShape({
id: t.id,
x: t.x,
y: t.y,
width: t.width,
height: t.height
});
modeling.createShape(shape, { x: shape.x, y: shape.y }, root);
}

if (index < tasks.length) {
requestAnimationFrame(processChunk);
} else {

setTimeout(() => {
minimap._update();
}, 100);
}
}

requestAnimationFrame(processChunk);
}));

});


Expand Down