Skip to content

Commit

Permalink
Allow to add/remove view config, fixes #1431
Browse files Browse the repository at this point in the history
  • Loading branch information
ivmartel committed Jun 30, 2023
1 parent 08a655e commit 1d7beec
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 11 deletions.
114 changes: 103 additions & 11 deletions src/app/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -656,9 +656,91 @@ export class App {
this.#createLayerGroups(configs);
}

/**
* Add a data view config.
*
* @param {number} dataId The data id.
* @param {object} config The view configuration.
*/
addDataViewConfig(dataId, config) {
// add to list
const configs = this.#options.dataViewConfigs;
if (typeof configs[dataId] === 'undefined') {
configs[dataId] = [];
}
const equalDivId = function (item) {
return item.divId === config.divId;
};
const itemIndex = configs[dataId].findIndex(equalDivId);
if (itemIndex === -1) {
this.#options.dataViewConfigs[dataId].push(config);
} else {
throw new Error('Duplicate view sconfig for data ' + dataId +
' and div ' + config.divId);
}

// data is loaded, create view
if (typeof this.#dataController.get(dataId) !== 'undefined') {
const lg = this.#stage.getLayerGroupByDivId(config.divId);
if (typeof lg === 'undefined') {
// create layer group
this.#createLayerGroup(config);
} else {
// add view
this.#addViewLayer(dataId, config);
}
}
}

/**
* Remove a data view config.
*
* @param {number} dataId The data id.
* @param {object} config The view configuration.
*/
removeDataViewConfig(dataId, config) {
// remove from list
const configs = this.#options.dataViewConfigs;
if (typeof configs[dataId] === 'undefined') {
// no config for dataId
return;
}
const equalDivId = function (item) {
return item.divId === config.divId;
};
const itemIndex = configs[dataId].findIndex(equalDivId);
if (itemIndex === -1) {
// no config for divId
return;
}
configs[dataId].splice(itemIndex, 1);

// data is loaded, remove view
if (typeof this.#dataController.get(dataId) !== 'undefined') {
const lg = this.#stage.getLayerGroupByDivId(config.divId);
if (typeof lg !== 'undefined') {
const vls = lg.getViewLayersByDataIndex(dataId);
if (vls.length === 1) {
lg.removeLayer(vls[0]);
} else {
throw new Error('Expected one view layer, got ' + vls.length);
}
const dls = lg.getDrawLayersByDataIndex(dataId);
if (dls.length === 1) {
lg.removeLayer(dls[0]);
} else {
throw new Error('Expected one draw layer, got ' + dls.length);
}
if (lg.getNumberOfLayers() === 0) {
this.#stage.removeLayerGroup(lg);
}
}
}
}

/**
* Create layer groups according to a data view config:
* adds them to stage and bind them.
* adds them to stage and binds them.
*
* @param {object} dataViewConfigs The data view config.
*/
Expand All @@ -671,22 +753,32 @@ export class App {
const viewConfig = dataConfigs[j];
// view configs can contain the same divIds, avoid duplicating
if (!divIds.includes(viewConfig.divId)) {
// create new layer group
const element = document.getElementById(viewConfig.divId);
const layerGroup = this.#stage.addLayerGroup(element);
// bind events
this.#bindLayerGroupToApp(layerGroup);
// optional orientation
if (typeof viewConfig.orientation !== 'undefined') {
layerGroup.setTargetOrientation(
getMatrixFromName(viewConfig.orientation));
}
this.#createLayerGroup(viewConfig);
divIds.push(viewConfig.divId);
}
}
}
}

/**
* Create a layer group according to a view config:
* adds it to stage and binds it.
*
* @param {object} viewConfig The view config.
*/
#createLayerGroup(viewConfig) {
// create new layer group
const element = document.getElementById(viewConfig.divId);
const layerGroup = this.#stage.addLayerGroup(element);
// bind events
this.#bindLayerGroupToApp(layerGroup);
// optional orientation
if (typeof viewConfig.orientation !== 'undefined') {
layerGroup.setTargetOrientation(
getMatrixFromName(viewConfig.orientation));
}
}

/**
* Set the layer groups binders.
*
Expand Down
61 changes: 61 additions & 0 deletions src/gui/layerGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,24 @@ export class LayerGroup {
viewLayer.addEventListener('renderend', this.#fireEvent);
}

/**
* Un-bind a view layer events to this.
*
* @param {ViewLayer} viewLayer The view layer to unbind.
*/
#unbindViewLayer(viewLayer) {
// listen to position change to update other group layers
viewLayer.removeEventListener(
'positionchange', this.updateLayersToPositionChange);
// propagate view viewLayer-layer events
for (let j = 0; j < viewEventNames.length; ++j) {
viewLayer.removeEventListener(viewEventNames[j], this.#fireEvent);
}
// propagate viewLayer events
viewLayer.removeEventListener('renderstart', this.#fireEvent);
viewLayer.removeEventListener('renderend', this.#fireEvent);
}

/**
* Bind draw layer events to this.
*
Expand All @@ -565,6 +583,17 @@ export class LayerGroup {
drawLayer.addEventListener('drawdelete', this.#fireEvent);
}

/**
* Un-bind a draw layer events to this.
*
* @param {DrawLayer} drawLayer The draw layer to unbind.
*/
#unbindDrawLayer(drawLayer) {
// propagate drawLayer events
drawLayer.removeEventListener('drawcreate', this.#fireEvent);
drawLayer.removeEventListener('drawdelete', this.#fireEvent);
}

/**
* Get the next layer DOM div.
*
Expand Down Expand Up @@ -595,6 +624,38 @@ export class LayerGroup {
}
}

/**
* Remove a layer from this layer group.
*
* @param {ViewLayer | DrawLayer} layer The layer to remove.
*/
removeLayer(layer) {
// find layer
const index = this.#layers.findIndex((item) => item === layer);
if (index === -1) {
throw new Error('Cannot find layer');
}
// unbind and update active index
if (layer instanceof ViewLayer) {
this.#unbindViewLayer(layer);
if (this.#activeViewLayerIndex === index) {
this.#activeViewLayerIndex = undefined;
}
} else {
this.#unbindDrawLayer(layer);
if (this.#activeDrawLayerIndex === index) {
this.#activeDrawLayerIndex = undefined;
}
}
// remove from storage
this.#layers.splice(index, 1);
// update html
const layerDiv = document.getElementById(layer.getId());
if (layerDiv) {
layerDiv.remove();
}
}

/**
* Show a crosshair at a given position.
*
Expand Down
25 changes: 25 additions & 0 deletions src/gui/stage.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,31 @@ export class Stage {
this.#activeLayerGroupIndex = null;
}

/**
* Remove a layer group from this stage.
*
* @param {LayerGroup} layerGroup The layer group to remove.
*/
removeLayerGroup(layerGroup) {
// find layer
const index = this.#layerGroups.findIndex((item) => item === layerGroup);
if (index === -1) {
throw new Error('Cannot find layerGroup');
}
// unbind
this.unbindLayerGroups();
// empty layer group
layerGroup.empty();
// remove from storage
this.#layerGroups.splice(index, 1);
// update active index
if (this.#activeLayerGroupIndex === index) {
this.#activeLayerGroupIndex = undefined;
}
// bind
this.bindLayerGroups();
}

/**
* Reset the stage: calls reset on all layer groups.
*/
Expand Down
59 changes: 59 additions & 0 deletions tests/gui/layerGroup.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
LayerGroup,
getLayerDivId,
getLayerDetailsFromLayerDivId
} from '../../src/gui/layerGroup';
Expand Down Expand Up @@ -39,3 +40,61 @@ QUnit.test('Test LayerGroup string id.', function (assert) {
assert.equal(details01.layerId, theoDetails01.layerId,
'getLayerDetailsFromLayerDivId layerId #01');
});

/**
* Tests for {@link LayerGroup} creation.
*
* @function module:tests/gui~LayerGroup
*/
QUnit.test('Test LayerGroup.', function (assert) {
const element00 = document.createElement('div');
element00.id = 'layerGroup00';
const layerGroup00 = new LayerGroup(element00);
assert.equal(layerGroup00.getNumberOfLayers(), 0,
'new layerGroup has no layers');
assert.equal(layerGroup00.getDivId(), element00.id,
'new layerGroup div id');
});


/**
* Tests for {@link LayerGroup} add/remove view layer.
*
* @function module:tests/gui~LayerGroup
*/
QUnit.test('Test LayerGroup add/remove view layer.', function (assert) {
const element00 = document.createElement('div');
element00.id = 'layerGroup00';
const layerGroup00 = new LayerGroup(element00);
assert.equal(layerGroup00.getNumberOfLayers(), 0,
'new layerGroup has no layers');

const vl00 = layerGroup00.addViewLayer();
assert.equal(layerGroup00.getNumberOfLayers(), 1,
'layerGroup has one view layers after add');

layerGroup00.removeLayer(vl00);
assert.equal(layerGroup00.getNumberOfLayers(), 0,
'layerGroup has no view layers after remove');
});

/**
* Tests for {@link LayerGroup} add/remove draw layer.
*
* @function module:tests/gui~LayerGroup
*/
QUnit.test('Test LayerGroup add/remove draw layer.', function (assert) {
const element00 = document.createElement('div');
element00.id = 'layerGroup00';
const layerGroup00 = new LayerGroup(element00);
assert.equal(layerGroup00.getNumberOfLayers(), 0,
'new layerGroup has no layers');

const dl00 = layerGroup00.addDrawLayer();
assert.equal(layerGroup00.getNumberOfLayers(), 1,
'layerGroup has one draw layers after add');

layerGroup00.removeLayer(dl00);
assert.equal(layerGroup00.getNumberOfLayers(), 0,
'layerGroup has no view layers after remove');
});

0 comments on commit 1d7beec

Please sign in to comment.