Skip to content
Merged
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
63 changes: 63 additions & 0 deletions client/src/MapStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
DisplayConfiguration,
LayerCollection,
NetCDFData,
NetCDFImageWorking,
NetCDFLayer,
RasterMapLayer,
SearchableVectorData,
Expand All @@ -34,6 +35,8 @@

public static proModeButtonEnabled = ref(true);

public static globalTime = ref(Math.floor(new Date().getTime() / 1000));

public static displayConfiguration: Ref<DisplayConfiguration> = ref(
{ default_displayed_layers: [], enabled_ui: ['Collections', 'Datasets', 'Metadata'], default_tab: 'Scenarios' },
);
Expand Down Expand Up @@ -69,6 +72,10 @@

public static visibleMapLayers: Ref<Set<string>> = ref(new Set());

// Net CDF Layers

public static visibleNetCDFLayers: Ref<NetCDFImageWorking[]> = ref([]);

public static selectedVectorMapLayers: Ref<VectorMapLayer[]> = computed(
() => MapStore.selectedMapLayers.value.filter((layer) => layer.type === 'vector'),
);
Expand Down Expand Up @@ -171,6 +178,27 @@

public static mapLayerFeatureGraphsVisible = ref(false);

public static vectorFeatureTableGraphVisible = ref(false);

public static vectorFeatureTableData: Ref<{ layerId: number, vectorFeatureId: number, defaultGraphs?: string[] } | null> = ref(null);

Check warning on line 183 in client/src/MapStore.ts

View workflow job for this annotation

GitHub Actions / lint-client

This line has a length of 135. Maximum allowed is 130

public static setVectorFeatureTableData = (layerId: number, vectorFeatureId: number, defaultGraphs?: string[]) => {
if (MapStore.mapLayerFeatureGraphsVisible.value) {
MapStore.mapLayerFeatureGraphsVisible.value = false;
}
MapStore.vectorFeatureTableData.value = {
layerId,
vectorFeatureId,
defaultGraphs,
};
MapStore.vectorFeatureTableGraphVisible.value = true;
};

public static clearVectorFeatureTableData = () => {
MapStore.vectorFeatureTableData.value = null;
MapStore.vectorFeatureTableGraphVisible.value = false;
};

// Graph color mapping implementation
public static enabledMapLayerFeatureColorMapping = ref(false);

Expand Down Expand Up @@ -353,4 +381,39 @@
}
}
};

// Graph Charts current Min/Max Values in unix_time
public static graphChartsMinMax = ref({
min: 0,
max: 0,
stepSize: 0,
});

public static timeLinked = ref(true);

public static updateChartsMinMax = (min: number, max: number, stepSize: number) => {
MapStore.graphChartsMinMax.value = { min, max, stepSize };
};

// Computes in Unix Time
public static globalTimeRange: Ref<{ min: number; max: number, stepSize: number }> = computed(() => {
let globalMin = Infinity;
let globalMax = -Infinity;
let stepSize = Infinity;
MapStore.visibleNetCDFLayers.value.forEach((layer) => {
if (layer.sliding) {
const { min, max } = layer.sliding;
const stepsize = layer.images.length;
stepSize = Math.min(stepSize, (max - min) / stepsize);
globalMin = Math.min(globalMin, min);
globalMax = Math.max(globalMax, max);
}
});
if ((MapStore.mapLayerFeatureGraphsVisible.value && MapStore.mapLayerFeatureGraphs.value.length) || MapStore.vectorFeatureTableGraphVisible.value) {

Check warning on line 412 in client/src/MapStore.ts

View workflow job for this annotation

GitHub Actions / lint-client

This line has a length of 152. Maximum allowed is 130
globalMin = Math.min(globalMin, MapStore.graphChartsMinMax.value.min);
globalMax = Math.max(globalMax, MapStore.graphChartsMinMax.value.max);
stepSize = Math.min(stepSize, MapStore.graphChartsMinMax.value.stepSize);
}
return { min: globalMin, max: globalMax, stepSize };
});
}
40 changes: 40 additions & 0 deletions client/src/api/UVDATApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
DerivedRegion,
DisplayConfiguration,
FeatureGraphData,
FeatureGraphs,
FeatureGraphsRequest,
FileItem,
LayerCollection,
LayerCollectionLayer,
Expand Down Expand Up @@ -538,6 +540,44 @@ export default class UVdatApi {
return response.data;
}

public static async getFeatureGraphsData(
payload: FeatureGraphsRequest,
): Promise<FeatureGraphs[]> {
const {
tableTypes,
vectorFeatureId,
xAxes = ['index'],
yAxes = ['mean_va'],
indexers = [],
display = ['data', 'trendLine'],
confidenceLevel = 95,
aggregate = false,
movingAverage,
} = payload;

const params = new URLSearchParams();

tableTypes.forEach((type) => params.append('tableType', type));
xAxes.forEach((x) => params.append('xAxis', x));
yAxes.forEach((y) => params.append('yAxis', y));
indexers.forEach((indexer) => params.append('indexer', indexer));
display.forEach((d) => params.append('display', d));

params.append('vectorFeatureId', vectorFeatureId.toString());
params.append('confidenceLevel', confidenceLevel.toString());
params.append('aggregate', aggregate.toString());
if (movingAverage !== undefined) {
params.append('movingAverage', movingAverage.toString());
}

const response = await UVdatApi.apiClient.get<FeatureGraphs[]>(
'/vectorfeature/tabledata/feature-graphs/',
{ params },
);

return response.data;
}

public static async getMapLayerFeatureGraphData(
tableType: string,
mapLayerId: number,
Expand Down
9 changes: 7 additions & 2 deletions client/src/components/FeatureSelection/VectorFeatureChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { throttle } from 'lodash';
import UVdatApi from '../../api/UVDATApi';
import { FeatureGraphData, VectorFeatureTableGraph } from '../../types';
import { renderVectorFeatureGraph } from './vectorFeatureGraphUtils';
import MapStore from '../../MapStore';

export default defineComponent({
name: 'FeatureGraph',
Expand Down Expand Up @@ -66,7 +67,6 @@ export default defineComponent({
confidenceLevel.value,
false,
movingAverageValue.value,

);
if (data.graphs && Object.keys(data.graphs).length === 0) {
noGraphData.value = true;
Expand Down Expand Up @@ -157,6 +157,10 @@ export default defineComponent({
movingAverageValue,
], throttledUpateDialogGraph);

const openBottomGraph = () => {
MapStore.setVectorFeatureTableData(props.mapLayerId, props.vectorFeatureId, [props.graphInfo.name]);
};

return {
graphContainer,
graphDialogContainer,
Expand All @@ -171,6 +175,7 @@ export default defineComponent({
movingAverageEnabled,
movingAverageValue,
maxMovingAverage,
openBottomGraph,
};
},
});
Expand All @@ -184,7 +189,7 @@ export default defineComponent({
</v-alert>
</div>
<div v-if="graphData">
<v-btn color="primary" size="x-small" @click="openDialog">
<v-btn color="primary" size="x-small" @click="openBottomGraph">
View Larger Graph
</v-btn>
</div>
Expand Down
14 changes: 10 additions & 4 deletions client/src/components/FeatureSelection/vectorFeatureGraphUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const renderVectorFeatureGraph = (
container: SVGSVGElement,
options?: {
specificGraphKey?: number;
colors?: Record<number, string>;
colors?: Record<number | string, string>;
xAxisLabel?: string;
yAxisLabel?: string;
showXYValuesOnHover?: boolean;
Expand All @@ -21,10 +21,11 @@ const renderVectorFeatureGraph = (
showTrendline?: boolean;
showMovingAverage?: boolean;
showConfidenceInterval?: boolean;
useKeyTooltip?: boolean;
},
baseHeight = 400,
) => {
const outputColorMapping: Record<number, string> = {};
const outputColorMapping: Record<number | string, string> = {};
const localContainer = container;
if (!localContainer || !data) return outputColorMapping;

Expand Down Expand Up @@ -94,7 +95,12 @@ const renderVectorFeatureGraph = (
const g = svg.append('g').attr('transform', `translate(${margin.left},${margin.top})`);

const colorScale = d3.scaleOrdinal(d3.schemeCategory10);
const graphKeys = Object.keys(graphsToRender).map(Number);
const graphKeys = Object.keys(graphsToRender).map((item) => {
if (!Number.isNaN(parseInt(item, 10))) {
return parseInt(item, 10);
}
return item;
});
const tooltipGroup = g.append('g')
.attr('opacity', 0)
.attr('pointer-events', 'none');
Expand Down Expand Up @@ -148,7 +154,7 @@ const renderVectorFeatureGraph = (
.on('mousemove', (event) => {
const [mouseX, mouseY] = d3.pointer(event);

const tooltipTextContent = graph.indexer.toString();
const tooltipTextContent = options?.useKeyTooltip ? key.toString() : graph.indexer.toString();
tooltipText.text(tooltipTextContent)
.call((text) => {
// Adjust the background size based on text width
Expand Down
48 changes: 43 additions & 5 deletions client/src/components/MapLegends/ControlsKey.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
<script lang="ts">
import {
computed, defineComponent,
watch,
} from 'vue';
import { throttle } from 'lodash';
import GlobalTime from './GlobalTime.vue';
import {
AnnotationTypes,
NetCDFLayer,
Expand All @@ -13,12 +15,15 @@ import {
VectorMapLayer,
} from '../../types'; // Import your defined types
import MapStore from '../../MapStore';
import { updateNetCDFLayer, visibleNetCDFLayers } from '../../map/mapNetCDFLayer';
import { updateNetCDFLayer } from '../../map/mapNetCDFLayer';
import { getRasterLayerDisplayConfig, getVectorLayerDisplayConfig } from '../../utils';
import { updateLayer } from '../../map/mapLayers';

export default defineComponent({
name: 'ControlsKey',
components: {
GlobalTime,
},
props: {
vectorLayers: {
type: Array as () => VectorMapLayer[],
Expand Down Expand Up @@ -73,7 +78,7 @@ export default defineComponent({
// Compute NetCDF Layer Keys
const stepIndexMap: Record<string, { length: number, currentIndex: number }> = {};
const resamplingMap: Record<string, 'linear' | 'nearest'> = {};
visibleNetCDFLayers.value.forEach((item) => {
MapStore.visibleNetCDFLayers.value.forEach((item) => {
const found = props.netcdfLayers.find((layer) => layer.id === item.netCDFLayer);
if (found) {
const { opacity } = item;
Expand Down Expand Up @@ -123,7 +128,7 @@ export default defineComponent({

const stepMapping = computed(() => {
const mappedStepMapping: Record<string, Record<number, string | number>> = {};
visibleNetCDFLayers.value.forEach((item) => {
MapStore.visibleNetCDFLayers.value.forEach((item) => {
const foundLayer = props.netcdfLayers.find((layer) => layer.id === item.netCDFLayer);
mappedStepMapping[`netcdf_${foundLayer?.id}`] = {};
const mapSlicer: Record<number, string | number> = {};
Expand Down Expand Up @@ -174,7 +179,7 @@ export default defineComponent({
});
}
if (item.type === 'netcdf') {
const found = visibleNetCDFLayers.value.find((layer) => item.id === layer.netCDFLayer);
const found = MapStore.visibleNetCDFLayers.value.find((layer) => item.id === layer.netCDFLayer);
if (found) {
found.opacity = val;
updateNetCDFLayer(item.id, { opacity: val });
Expand All @@ -194,26 +199,59 @@ export default defineComponent({
};

const toggleResampling = (id: number) => {
const found = visibleNetCDFLayers.value.find((layer) => id === layer.netCDFLayer);
const found = MapStore.visibleNetCDFLayers.value.find((layer) => id === layer.netCDFLayer);
if (found) {
const val = found.resampling === 'linear' ? 'nearest' : 'linear';
found.resampling = val;
updateNetCDFLayer(id, { resampling: val });
}
};

watch(MapStore.globalTime, (newVal) => {
if (!MapStore.timeLinked.value) {
return;
}
props.netcdfLayers.forEach((netcdfLayer) => {
const found = MapStore.visibleNetCDFLayers.value.find((layer) => layer.netCDFLayer === netcdfLayer.id);
if (found) {
// now we need to find the closest index to the current time
const { min } = found.sliding;
const stepSize = found.sliding.step;
const currentIndex = Math.round((newVal - min) / stepSize);
if (currentIndex >= 0 && currentIndex < found.images.length) {
found.currentIndex = currentIndex;
throttledUpdateNetCDFLayer(netcdfLayer.id, currentIndex);
}
}
});
});

const globalTimeEnabled = computed(() => {
let enabled = false;
if (props.netcdfLayers.length > 0) {
enabled = true;
}
return enabled;
});
return {
processedLayers,
iconMapper,
updateOpacity,
throttledUpdateNetCDFLayer,
stepMapping,
toggleResampling,
globalTimeEnabled,
};
},
});
</script>

<template>
<v-card v-if="globalTimeEnabled" class="pa-0 ma-0 mb-2">
<v-card-text class="pa-0 ma-0">
<global-time />
</v-card-text>
</v-card>
<v-card
v-for="(item, index) in processedLayers"
:key="`opacity_${index}`"
Expand Down
Loading
Loading