labo-components
Version:
282 lines (243 loc) • 8.65 kB
JavaScript
import { ANNOTATION_TARGET, CUSTOM } from "../../util/AnnotationConstants";
import Strings from "./_Strings";
const SEGMENT_LAYERS = "segment-layers";
class SegmentLayers {
constructor({ annotationClient }) {
this.annotationClient = annotationClient;
window.segmentLayers = this;
}
// Get an array of segments by given layer id
getSegments(id) {
const annotations = this.annotationClient.annotations;
// All user segments
return annotations
? annotations.filter(
(annotation) =>
annotation.target.type === ANNOTATION_TARGET.SEGMENT &&
(annotation.target.layerId === id || // number corresponding with layerId
(id === 0 && // add annotations with invalid layerId to layerId 0
(!annotation.target.layerId || // fallback for undefined
!(
typeof annotation.target.layerId ==
"number"
)))) // fallback for non numbers
)
: [];
}
// Get all unique layer ids from given annotations
getLayerIds = () => {
const annotations = this.annotationClient.annotations;
const ids = {};
let id = "";
annotations.forEach((annotation) => {
if (
annotation.target &&
annotation.target.type === ANNOTATION_TARGET.SEGMENT
) {
id = annotation.target.layerId;
// undefined -> 0
if (id == undefined) {
id = 0;
}
// not a number -> Parse
if (typeof id != "number") {
id = parseInt(id);
// NaN -> 0
if (isNaN(id)) {
id = 0;
}
}
ids[id] = true;
}
});
return Object.keys(ids)
.map((id) => parseInt(id))
.sort();
};
getLayerConfigData() {
const annotations = this.annotationClient.annotations;
// get (first) media object annotation
const annotation = annotations.find(
(annotation) =>
annotation.target.type === ANNOTATION_TARGET.MEDIAOBJECT
);
// Require an annotation with body
if (!annotation || !annotation.body) {
return null;
}
// Find the layer template
return annotation.body.find((body) => {
if (body.annotationType === CUSTOM && body.role == SEGMENT_LAYERS) {
return true;
}
});
}
// Get annotation layer config from MediaObject annotation
getLayerConfig() {
const data = this.getLayerConfigData();
return data && data.data ? data.data : {};
}
// Get all layers
getLayers() {
// layer data from media object data annotation
const layers = this.getLayerConfig();
// layer ids currently in use
const layerIds = this.getLayerIds();
// merge
layerIds.forEach((id) => {
if (!(id in layers)) {
layers[id] = "Layer " + id;
}
});
return layers;
}
getLayersSorted() {
const layers = this.getLayers();
return Object.keys(layers)
.sort((a, b) => {
const titleA = layers[a].toLowerCase();
const titleB = layers[b].toLowerCase();
return titleA == titleB ? 0 : titleA > titleB ? 1 : -1;
})
.map((id) => ({ id: parseInt(id), title: layers[id] }));
}
// Get first layer id available, default to 0
getFirstLayerId() {
const layers = this.getLayers();
const keys = Object.keys(layers);
return keys.length > 0 ? keys[0] : 0;
}
// Get current MediaObject target annotation, or create a new one if needed
getOrCreateMediaObjectAnnotation = async () => {
// Current
let targetAnnotation = this.annotationClient.annotations.filter(
(annotation) =>
// current mediaObject
annotation.target &&
annotation.target.type === ANNOTATION_TARGET.MEDIAOBJECT
);
if (targetAnnotation.length > 0) {
return targetAnnotation[0];
}
// create target annotation
targetAnnotation = this.annotationClient.newAnnotation(
ANNOTATION_TARGET.MEDIAOBJECT,
false
);
if (!targetAnnotation) {
console.error("Could not create a target annotation");
return null;
}
this.annotationClient.edit(targetAnnotation);
await this.annotationClient.save(true, false);
return this.annotationClient.activeAnnotation;
};
// Create a custom annotation for the layerconfig
createLayerConfig = async () => {
const targetAnnotation = await this.getOrCreateMediaObjectAnnotation();
if (!targetAnnotation) {
console.error("Could not create layer config");
return;
}
const data = {
annotationType: CUSTOM,
role: SEGMENT_LAYERS,
data: {}, // { 0: "My layer name" }
};
await this.annotationClient.saveBodyElement(
data,
true,
true,
targetAnnotation
);
};
// Save layer config to custom annotation
saveLayerConfig = async (config) => {
const targetAnnotation = await this.getOrCreateMediaObjectAnnotation();
if (!targetAnnotation) {
console.error("Could not create layer config");
return;
}
let data = this.getLayerConfigData();
if (!data) {
data = {
annotationType: CUSTOM,
role: SEGMENT_LAYERS,
};
}
data.data = config;
await this.annotationClient.saveBodyElement(
data,
true,
true,
targetAnnotation
);
};
// Get layer config; if no layer config has been created yet, add it to the annotation data
getOrCreateLayerConfig = async () => {
let config = this.getLayerConfig();
if (Object.keys(config).length > 0) {
return config;
}
// create new
await this.createLayerConfig();
return this.getLayerConfig();
};
// Add a new segment layer to the config/data
// space in title intentional; puts the new layer first in sort order
addLayer = async (title = " My segment layer") => {
const config = await this.getLayerConfig();
let id = 0;
// Check for id in config until there is an empty spot
while (id in config) {
id++;
}
config[id] = title;
await this.saveLayerConfig(config);
};
// Callable as callback, prevents using the event as layer title
addEmptyLayer = async () => {
this.addLayer();
};
// Rename a layer with given id, title
renameLayer = async (id, title) => {
const config = await this.getLayerConfig();
config[id] = title;
await this.saveLayerConfig(config);
};
getLayerTitle(id) {
const config = this.getLayerConfig();
return id in config ? config[id] : "Layer " + id;
}
deleteLayer = async (id) => {
// delete segments
const segments = this.getSegments(id);
for (let i = 0, len = segments.length; i < len; i++) {
await this.annotationClient.delete(segments[i], true); // notify at last iteration i == len - 1
}
// delete from config
const config = await this.getLayerConfig();
if (id in config) {
delete config[id];
await this.saveLayerConfig(config);
}
};
deleteLayerWithCheck = async (id) => {
// Can not delete empty or static layer
if (id == null || id < 0) {
alert(Strings.BUTTON_DELETE_USER_LAYER_DENIED);
return;
}
if (
confirm(
Strings.BUTTON_DELETE_USER_LAYER_CONFIRM.replace(
"%LAYER_NAME%",
this.getLayerTitle(id)
)
)
) {
this.annotationClient.segmentLayers.deleteLayer(id);
}
};
}
export default SegmentLayers;