Skip to content

Commit

Permalink
add layer toggles for ms, KHz, species
Browse files Browse the repository at this point in the history
  • Loading branch information
BryonLewis committed Jan 29, 2024
1 parent 22c1809 commit f67988d
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 24 deletions.
5 changes: 0 additions & 5 deletions client/src/components/SpectrogramViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ export default defineComponent({
type: String as PropType<string | null>,
required: true,
},
grid: {
type: Boolean,
default: false,
},
},
emits: ["update:annotation", "create:annotation", "selected", "geoViewerRef", "hoverData", 'set-mode',],
setup(props, { emit }) {
Expand Down Expand Up @@ -198,7 +194,6 @@ export default defineComponent({
:spectro-info="spectroInfo"
:annotations="annotations"
:selected-id="selectedId"
:grid="grid"
@selected="clickSelected($event)"
@update:annotation="updateAnnotation($event)"
@create:annotation="createAnnotation($event)"
Expand Down
45 changes: 32 additions & 13 deletions client/src/components/geoJS/LayerManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import RectangleLayer from "./layers/rectangleLayer";
import LegendLayer from "./layers/legendLayer";
import TimeLayer from "./layers/timeLayer";
import FreqLayer from "./layers/freqLayer";
import SpeciesLayer from "./layers/speciesLayer";
import { cloneDeep } from "lodash";
import useState from "../../use/useState";
export default defineComponent({
Expand All @@ -33,14 +34,10 @@ export default defineComponent({
type: Boolean,
default: false,
},
grid: {
type: Boolean,
default: false,
}
},
emits: ['selected', 'update:annotation', 'create:annotation', 'set-cursor', 'set-mode'],
setup(props, { emit }) {
const { annotationState, setAnnotationState } = useState();
const { annotationState, setAnnotationState, layerVisibility, } = useState();
const selectedAnnotationId: Ref<null | number> = ref(null);
const hoveredAnnotationId: Ref<null | number> = ref(null);
const localAnnotations: Ref<SpectrogramAnnotation[]> = ref(cloneDeep(props.annotations));
Expand All @@ -51,6 +48,7 @@ export default defineComponent({
let legendLayer: LegendLayer;
let timeLayer: TimeLayer;
let freqLayer: FreqLayer;
let speciesLayer: SpeciesLayer;
const displayError = ref(false);
const errorMsg = ref('');
Expand Down Expand Up @@ -184,11 +182,30 @@ export default defineComponent({
rectAnnotationLayer.redraw();
}
if (!props.thumbnail) {
if (layerVisibility.value.includes('grid')) {
legendLayer.setGridEnabled(true);
} else {
legendLayer.setGridEnabled(false);
}
legendLayer.redraw();
timeLayer.formatData(localAnnotations.value);
timeLayer.redraw();
freqLayer.formatData(localAnnotations.value);
freqLayer.redraw();
if (layerVisibility.value.includes('time')) {
timeLayer.formatData(localAnnotations.value);
timeLayer.redraw();
} else {
timeLayer.disable();
}
if (layerVisibility.value.includes('freq')) {
freqLayer.formatData(localAnnotations.value);
freqLayer.redraw();
} else {
freqLayer.disable();
}
if (layerVisibility.value.includes('species')) {
speciesLayer.formatData(localAnnotations.value);
speciesLayer.redraw();
} else {
speciesLayer.disable();
}
}
if (editing.value && editingAnnotation.value) {
setTimeout(() => {
Expand Down Expand Up @@ -231,17 +248,19 @@ export default defineComponent({
timeLayer.formatData(localAnnotations.value);
freqLayer = new FreqLayer(props.geoViewerRef, event, props.spectroInfo);
freqLayer.formatData(localAnnotations.value);
speciesLayer = new SpeciesLayer(props.geoViewerRef, event, props.spectroInfo);
speciesLayer.formatData(localAnnotations.value);
legendLayer.redraw();
timeLayer.redraw();
freqLayer.redraw();
timeLayer.disable();
freqLayer.disable();
speciesLayer.disable();
}
}
});
watch(() => props.grid, () => {
watch(layerVisibility, () => {
if (!props.thumbnail && legendLayer) {
legendLayer.setGridEnabled(props.grid);
triggerUpdate();
}
});
Expand Down
120 changes: 120 additions & 0 deletions client/src/components/geoJS/layers/speciesLayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* eslint-disable class-methods-use-this */
import { SpectrogramAnnotation } from "../../../api/api";
import { SpectroInfo, spectroToGeoJSon } from "../geoJSUtils";
import { LayerStyle } from "./types";

interface TextData {
text: string;
x: number;
y: number;
offsetY?: number;
offsetX?: number;
}

export default class SpeciesLayer {

textData: TextData[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
textLayer: any;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
geoViewerRef: any;


// eslint-disable-next-line @typescript-eslint/no-explicit-any
event: (name: string, data: any) => void;

spectroInfo: SpectroInfo;

textStyle: LayerStyle<TextData>;


// eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
geoViewerRef: any,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
event: (name: string, data: any) => void,
spectroInfo: SpectroInfo
) {
this.geoViewerRef = geoViewerRef;
this.spectroInfo = spectroInfo;
this.textData = [];
this.event = event;
//Only initialize once, prevents recreating Layer each edit
const layer = this.geoViewerRef.createLayer("feature", {
features: ["text"],
});
this.textLayer = layer
.createFeature("text")
.text((data: TextData) => data.text)
.position((data: TextData) => ({ x: data.x, y: data.y }));


this.textStyle = this.createTextStyle();
}


formatData(annotationData: SpectrogramAnnotation[]) {
this.textData = [];
annotationData.forEach((annotation: SpectrogramAnnotation) => {
const polygon = spectroToGeoJSon(annotation, this.spectroInfo);
const [xmin, ymin] = polygon.coordinates[0][0];
const [xmax, ymax] = polygon.coordinates[0][2];
// For the compressed view we need to filter out default or NaN numbers
if (Number.isNaN(xmax) || Number.isNaN(xmin) || Number.isNaN(ymax) || Number.isNaN(ymin)) {
return;
}
if (xmax === -1 && ymin === -1 && ymax === -1 && xmin === -1) {
return;
}
let textOffset = 0;
const species = annotation.species;
if (species) {
for (let i =0; i< species.length; i += 1) {
const specie = species[i];
this.textData.push({
text: `${specie.common_name}`,
x: xmin + (xmax-xmin) /2.0,
y: ymax ,
offsetX:0,
offsetY: -5 + textOffset,
});
textOffset -= 15;

}
}
});
}

redraw() {
// add some styles
this.textLayer.data(this.textData).style(this.createTextStyle()).draw();
}

disable() {
this.textLayer.data([]).draw();
}


createTextStyle(): LayerStyle<TextData> {
return {
...{
strokeColor: "yellow",
strokeWidth: 2.0,
antialiasing: 0,
stroke: true,
uniformPolygon: true,
fill: false,
},
color: () => {
return "white";
},
offset: (data) => ({
x: data.offsetX || 0,
y: data.offsetY || 0,
}),
textAlign: 'center',
};
}
}
6 changes: 3 additions & 3 deletions client/src/components/geoJS/layers/timeLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default class TimeLayer {
formatData(annotationData: SpectrogramAnnotation[]) {
this.textData = [];
this.lineData = [];
const lineDist = 8;
const lineDist = 12;
annotationData.forEach((annotation: SpectrogramAnnotation) => {
const polygon = spectroToGeoJSon(annotation, this.spectroInfo);
const {start_time, end_time } = annotation;
Expand Down Expand Up @@ -112,14 +112,14 @@ export default class TimeLayer {
x: xmin,
y: ymin + lineDist,
offsetX: 0,
offsetY: 0,
offsetY: 5,
});
this.textData.push({
text: `${end_time}ms`,
x: xmax,
y: ymin + lineDist,
offsetX: 0,
offsetY: 0,
offsetY: 5,
});
});
}
Expand Down
19 changes: 18 additions & 1 deletion client/src/use/useState.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
import { ref, Ref } from 'vue';
import { cloneDeep } from 'lodash';

const annotationState: Ref<AnnotationState> = ref('');
type LayersVis = 'time' | 'freq' | 'species' |'grid';
const layerVisibility: Ref<LayersVis[]> = ref([]);

type AnnotationState = '' | 'editing' | 'creating';
export default function useState() {
const setAnnotationState = (state: AnnotationState) => {
annotationState.value = state;
};
return {
function toggleLayerVisibility(value: LayersVis) {
const index = layerVisibility.value.indexOf(value);
const clone = cloneDeep(layerVisibility.value);
if (index === -1) {
// If the value is not present, add it
clone.push(value);
} else {
// If the value is present, remove it
clone.splice(index, 1);
}
layerVisibility.value = clone;
}
return {
annotationState,
setAnnotationState,
toggleLayerVisibility,
layerVisibility,
};
}

51 changes: 49 additions & 2 deletions client/src/views/Spectrogram.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import AnnotationList from "../components/AnnotationList.vue";
import AnnotationEditor from "../components/AnnotationEditor.vue";
import ThumbnailViewer from "../components/ThumbnailViewer.vue";
import { watch } from "vue";
import useState from "../use/useState";
export default defineComponent({
name: "Spectrogram",
components: {
Expand All @@ -30,6 +30,7 @@ export default defineComponent({
},
},
setup(props) {
const { toggleLayerVisibility, layerVisibility } = useState();
const image: Ref<HTMLImageElement> = ref(new Image());
const spectroInfo: Ref<SpectroInfo | undefined> = ref();
const annotations: Ref<SpectrogramAnnotation[] | undefined> = ref([]);
Expand Down Expand Up @@ -89,6 +90,9 @@ export default defineComponent({
}
return null;
});
watch(gridEnabled, () => {
toggleLayerVisibility('grid');
});
onMounted(() => loadData());
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const parentGeoViewerRef: Ref<any> = ref(null);
Expand Down Expand Up @@ -134,10 +138,12 @@ export default defineComponent({
setParentGeoViewer,
setHoverData,
setMode,
toggleLayerVisibility,
speciesList,
selectedAnnotation,
parentGeoViewerRef,
gridEnabled,
layerVisibility,
timeRef,
freqRef,
mode,
Expand Down Expand Up @@ -170,6 +176,48 @@ export default defineComponent({
<span> {{ mode }}</span>
</v-col>
<v-spacer />
<v-tooltip bottom>
<template #activator="{ props: subProps }">
<v-icon
v-bind="subProps"
size="35"
class="mr-5 mt-5"
:color="layerVisibility.includes('species') ? 'blue' : ''"
@click="toggleLayerVisibility('species')"
>
mdi-bat
</v-icon>
</template>
<span> Turn Species Label On/Off</span>
</v-tooltip>
<v-tooltip bottom>
<template #activator="{ props: subProps }">
<v-btn
v-bind="subProps"
size="35"
class="mr-5 mt-5"
:color="layerVisibility.includes('time') ? 'blue' : ''"
@click="toggleLayerVisibility('time')"
>
<h3>ms</h3>
</v-btn>
</template>
<span> Turn Time Label On/Off</span>
</v-tooltip>
<v-tooltip bottom>
<template #activator="{ props: subProps }">
<v-btn
v-bind="subProps"
size="35"
class="mr-5 mt-5"
:color="layerVisibility.includes('freq') ? 'blue' : ''"
@click="toggleLayerVisibility('freq')"
>
<h3>KHz</h3>
</v-btn>
</template>
<span> Turn Time Label On/Off</span>
</v-tooltip>
<v-tooltip bottom>
<template #activator="{ props: subProps }">
<v-icon
Expand Down Expand Up @@ -207,7 +255,6 @@ export default defineComponent({
:recording-id="id"
:annotations="annotations"
:selected-id="selectedId"
:grid="gridEnabled"
@selected="setSelection($event)"
@create:annotation="getAnnotationsList($event)"
@update:annotation="getAnnotationsList()"
Expand Down

0 comments on commit f67988d

Please sign in to comment.