Loading src/components/StickChart.vue +30 −65 Original line number Diff line number Diff line Loading @@ -46,27 +46,27 @@ export default { props: { chartID: { type: String, required: true required: true, }, stickID: { type: String, required: true required: true, }, cameraID: { type: String, required: true required: true, }, height: { type: Number, required: true } required: true, }, }, data() { return { width: 1000, margin: { top: 15, bottom: 20, left: 30, right: 20 }, scaleExtent: [1, Infinity], datapointLineWidth: 1 datapointLineWidth: 1, } }, computed: { Loading Loading @@ -101,7 +101,7 @@ export default { cssVars() { return { '--chart-margin-left': this.margin.left + 'px', '--chart-margin-top': this.margin.top + 'px' '--chart-margin-top': this.margin.top + 'px', } }, // --- Loading Loading @@ -140,10 +140,7 @@ export default { // --- Scales --- xScale() { return d3 .scaleUtc() .domain(this.timespan) .range(this.rangeX) return d3.scaleUtc().domain(this.timespan).range(this.rangeX) }, xScaleZoomed() { const transform = this.normalizedSelection2Transform( Loading Loading @@ -172,7 +169,7 @@ export default { timespan() { return [ this.$store.getters.timespanStart, this.$store.getters.timespanEnd this.$store.getters.timespanEnd, ] }, maxSnowHeight() { Loading @@ -195,9 +192,9 @@ export default { this.$store.dispatch('setActivePoint', { stickID: this.stickID, cameraID: this.cameraID, imageName imageName, }) } }, }, // Check visibility of the chart. No need to rerender hidden chart. Loading Loading @@ -226,19 +223,19 @@ export default { if (this.chartData) { return d3 .quadtree() .x(d => { .x((d) => { // Ask for x coordinate in the canvas coordinate system. let dateTime = this.chartData[d].dateTime return this.xScaleZoomed(new Date(dateTime)) }) .y(d => { .y((d) => { return this.yScale( this.chartData[d].sticks[this.stickID].snowHeight ) }) .extent([ [this.margin.left, 0], [this.width - this.margin.right, this.height] [this.width - this.margin.right, this.height], ]) .addAll(Object.keys(this.chartData)) } Loading @@ -253,20 +250,17 @@ export default { .scaleExtent(this.scaleExtent) .extent([ [this.margin.left, 0], [this.width - this.margin.right, this.height] [this.width - this.margin.right, this.height], ]) .translateExtent([ [this.margin.left, 0], [this.width - this.margin.right, 0] [this.width - this.margin.right, 0], ]) .on('zoom', this.zoomed) }, // --- // --- Filters --- // filterImageProcessed() { // return this.$store.state.filters.imageProcessed // }, filterIsDay() { return this.$store.state.filters.isDay }, Loading @@ -287,18 +281,10 @@ export default { }, filterImageDiscarded() { return this.$store.state.filters.imageDiscarded } // filterImageUsedForSvmTraining() { // return this.$store.state.filters.imageUsedForSvmTraining // } }, // --- }, watch: { // filterImageProcessed() { // if (this.isVisible) { // this.redrawPoints(this.xScaleZoomed) // } // }, filterIsDay() { if (this.isVisible) { this.redrawPoints(this.xScaleZoomed) Loading Loading @@ -334,11 +320,6 @@ export default { this.redrawPoints(this.xScaleZoomed) } }, // filterImageUsedForSvmTraining() { // if (this.isVisible) { // this.redrawPoints(this.xScaleZoomed) // } // }, activeImageName(imageName) { if (imageName) { this.$activePoint.attr('visibility', 'visible') Loading Loading @@ -395,7 +376,7 @@ export default { } this.redrawPoints(this.xScaleZoomed) } } }, }, methods: { handleResize({ width }) { Loading Loading @@ -487,22 +468,12 @@ export default { g.attr( 'transform', `translate(0,${this.height - this.margin.bottom})` ).call( d3 .axisBottom(x) .ticks(10) .tickSizeOuter(0) ) ).call(d3.axisBottom(x).ticks(10).tickSizeOuter(0)) }, yAxis(g, y) { g.attr('transform', `translate(${this.margin.left},0)`) .call( d3 .axisLeft(y) .ticks(5) .tickSizeOuter(0) ) .call(g => .call(d3.axisLeft(y).ticks(5).tickSizeOuter(0)) .call((g) => g .select('.tick:last-of-type text') .clone() Loading Loading @@ -530,8 +501,8 @@ export default { opacity = 0.2 } const timestamp = this.chartData[imageName].dateTime const snowHeight = this.chartData[imageName].sticks[this.stickID] .snowHeight const snowHeight = this.chartData[imageName].sticks[this.stickID].snowHeight const type = this.stickType(imageName) if (type.type === 'cross') { this.drawCross( Loading Loading @@ -665,8 +636,8 @@ export default { for (const image in this.chartData) { if (Object.hasOwnProperty.call(this.chartData, image)) { const timestamp = this.chartData[image].dateTime const snowHeightAverage = this.chartData[image].sticks[this.stickID] .snowHeightAverage const snowHeightAverage = this.chartData[image].sticks[this.stickID].snowHeightAverage if (lastTimestamp != null) { this.drawLine( context, Loading Loading @@ -732,10 +703,7 @@ export default { this.$hoveredPoint.attr('visibility', 'visible') this.$hoveredPoint .select('circle') .attr('cx', px) .attr('cy', py) this.$hoveredPoint.select('circle').attr('cx', px).attr('cy', py) this.$hoveredPoint .select('line') Loading Loading @@ -763,10 +731,7 @@ export default { } this.$activePoint.attr('visibility', 'visible') this.$activePoint .select('circle') .attr('cx', px) .attr('cy', py) this.$activePoint.select('circle').attr('cx', px).attr('cy', py) this.$activePoint .select('line') Loading @@ -774,7 +739,7 @@ export default { .attr('y1', Math.min(py + this.datapointRadius, this.rangeY[0])) .attr('x2', px) .attr('y2', this.rangeY[0]) } }, }, mounted() { this.$chart Loading @@ -784,7 +749,7 @@ export default { .on('click', this.clicked) .on('mousedown', () => this.$hoveredPoint.attr('visibility', 'hidden')) .on('mouseup', () => this.$hoveredPoint.attr('visibility', 'visible')) .on('wheel', event => { .on('wheel', (event) => { this.$hoveredPoint.attr('visibility', 'hidden') // Prevent scrolling the whole page when using mouse wheel on chart. if ( Loading @@ -799,7 +764,7 @@ export default { this.$yAxis.call(this.yAxis, this.yScale) this.width = this.$chart.node().clientWidth } }, } </script> Loading src/components/image-dialog/DialogControl.vuedeleted 100644 → 0 +0 −0 Empty file deleted. src/store/actions.js +41 −14 Original line number Diff line number Diff line import DatasetService from '@/services/dataset-service' import SunCalc from 'suncalc' import Vue from 'vue' import gradientBackground from './gradient-background' const _sendPostRequest = (state, commit, webCmd, isCommit = false) => { Loading Loading @@ -121,7 +122,12 @@ export default { dispatch('buildImageChronology', cameraID) for (const imageName of Object.keys(data)) { for (const stickID of Object.keys(data[imageName].sticks)) { dispatch('updateSnowHeightAverage', { cameraID, imageName, stickID }) dispatch('updateSnowHeightAverage', { cameraID, imageName, stickID, usingMutations: false, }) } } }) Loading @@ -146,19 +152,32 @@ export default { updateSnowHeightAverage( { commit, state, getters }, { cameraID, imageName, stickID } { cameraID, imageName, stickID, usingMutations = true } ) { // Due to unreasonable number of mutations invoked at the start // (snow height average is computed for every image in the beginning), // I added the "usingMutations" flag. It is true by default. // The only time it's reasonable to switch it off is at the beginning, as mentioned. // If the stick is not visible, but there was snow in the picture, don't trust the average and therefore don't measure it. if ( !state.data[cameraID][imageName].sticks[stickID].visible && state.data[cameraID][imageName].weatherConditions === 1 ) { commit('UPDATE_SNOW_HEIGHT_AVERAGE', { if (usingMutations) { commit('SET_SNOW_HEIGHT_AVERAGE', { cameraID, imageName, stickID, average: -1, }) } else { Vue.set( state.data[cameraID][imageName].sticks[stickID], 'snowHeightAverage', -1 ) } return } Loading Loading @@ -188,12 +207,20 @@ export default { } } const average = count === 0 ? 0 : heightSum / count commit('UPDATE_SNOW_HEIGHT_AVERAGE', { if (usingMutations) { commit('SET_SNOW_HEIGHT_AVERAGE', { cameraID, imageName, stickID, average, }) } else { Vue.set( state.data[cameraID][imageName].sticks[stickID], 'snowHeightAverage', average ) } }, setImageDateTime({ state, commit }, { cameraID, imageName, dateTimeString }) { Loading src/store/index.js +13 −18 Original line number Diff line number Diff line Loading @@ -15,16 +15,11 @@ export default new Vuex.Store({ //Format: stickID: { // x: number, // y: number, // positionMean: { // cameraID: { // top: [number, number], // bottom: [number, number], // } //} // statusGUI: 'full' | 'compact' | 'minimized', // lengthCm: number, // labels: {cameraID: 'label', cameraID: 'label'}, // primaryCamera: 'cameraID'} // primaryCamera: 'cameraID' //} cameras: {}, // Format: cameraID: {x: number, y: number, statusGUI: 'full' | 'minimized'} timespan: { start: new Date(), end: new Date() }, Loading Loading @@ -88,23 +83,23 @@ export default new Vuex.Store({ astronomicalTwilight: '#ecd7db', nauticalTwilight: '#f9e4d5', civilTwilight: '#fef1e0', day: '#fffff4' day: '#fffff4', }, controls: { showDaysGradient: true, showImageDialog: false, showFilters: false, showLegend: false, showHelpDialog: true showHelpDialog: true, }, zoomState: { selection: [0, 1], zoomingID: null zoomingID: null, // TODO: Add functions to manipulate this object into the object itself. }, redrawTrigger: false, // Value is not important, the change of state will trigger chart redrawing. server: { hasPendingChanges: false hasPendingChanges: false, }, filters: { imageProcessed: 2, Loading @@ -116,10 +111,10 @@ export default new Vuex.Store({ imageSticksEdited: 2, imageApproved: 2, imageDiscarded: 2, imageUsedForSvmTraining: 2 } imageUsedForSvmTraining: 2, }, }, mutations, actions, getters getters, }) src/store/mutations.js +4 −5 Original line number Diff line number Diff line Loading @@ -26,9 +26,8 @@ export default { state, { cameraID, imageName, recipCameraID, closestRecipImageName } ) { state.data[cameraID][imageName].reciprocalImageName[ recipCameraID ] = closestRecipImageName state.data[cameraID][imageName].reciprocalImageName[recipCameraID] = closestRecipImageName }, SET_STICK_SNOW_HEIGHT(state, { cameraID, imageName, stickID, snowHeight }) { // Vue.set( Loading Loading @@ -107,7 +106,7 @@ export default { SET_FILTER(state, { filterKind, value }) { state.filters[filterKind] = value }, UPDATE_SNOW_HEIGHT_AVERAGE(state, { cameraID, imageName, stickID, average }) { SET_SNOW_HEIGHT_AVERAGE(state, { cameraID, imageName, stickID, average }) { Vue.set( state.data[cameraID][imageName].sticks[stickID], 'snowHeightAverage', Loading @@ -116,5 +115,5 @@ export default { }, SET_SERVER_PENDING_CHANGES(state, value) { state.server.hasPendingChanges = value } }, } Loading
src/components/StickChart.vue +30 −65 Original line number Diff line number Diff line Loading @@ -46,27 +46,27 @@ export default { props: { chartID: { type: String, required: true required: true, }, stickID: { type: String, required: true required: true, }, cameraID: { type: String, required: true required: true, }, height: { type: Number, required: true } required: true, }, }, data() { return { width: 1000, margin: { top: 15, bottom: 20, left: 30, right: 20 }, scaleExtent: [1, Infinity], datapointLineWidth: 1 datapointLineWidth: 1, } }, computed: { Loading Loading @@ -101,7 +101,7 @@ export default { cssVars() { return { '--chart-margin-left': this.margin.left + 'px', '--chart-margin-top': this.margin.top + 'px' '--chart-margin-top': this.margin.top + 'px', } }, // --- Loading Loading @@ -140,10 +140,7 @@ export default { // --- Scales --- xScale() { return d3 .scaleUtc() .domain(this.timespan) .range(this.rangeX) return d3.scaleUtc().domain(this.timespan).range(this.rangeX) }, xScaleZoomed() { const transform = this.normalizedSelection2Transform( Loading Loading @@ -172,7 +169,7 @@ export default { timespan() { return [ this.$store.getters.timespanStart, this.$store.getters.timespanEnd this.$store.getters.timespanEnd, ] }, maxSnowHeight() { Loading @@ -195,9 +192,9 @@ export default { this.$store.dispatch('setActivePoint', { stickID: this.stickID, cameraID: this.cameraID, imageName imageName, }) } }, }, // Check visibility of the chart. No need to rerender hidden chart. Loading Loading @@ -226,19 +223,19 @@ export default { if (this.chartData) { return d3 .quadtree() .x(d => { .x((d) => { // Ask for x coordinate in the canvas coordinate system. let dateTime = this.chartData[d].dateTime return this.xScaleZoomed(new Date(dateTime)) }) .y(d => { .y((d) => { return this.yScale( this.chartData[d].sticks[this.stickID].snowHeight ) }) .extent([ [this.margin.left, 0], [this.width - this.margin.right, this.height] [this.width - this.margin.right, this.height], ]) .addAll(Object.keys(this.chartData)) } Loading @@ -253,20 +250,17 @@ export default { .scaleExtent(this.scaleExtent) .extent([ [this.margin.left, 0], [this.width - this.margin.right, this.height] [this.width - this.margin.right, this.height], ]) .translateExtent([ [this.margin.left, 0], [this.width - this.margin.right, 0] [this.width - this.margin.right, 0], ]) .on('zoom', this.zoomed) }, // --- // --- Filters --- // filterImageProcessed() { // return this.$store.state.filters.imageProcessed // }, filterIsDay() { return this.$store.state.filters.isDay }, Loading @@ -287,18 +281,10 @@ export default { }, filterImageDiscarded() { return this.$store.state.filters.imageDiscarded } // filterImageUsedForSvmTraining() { // return this.$store.state.filters.imageUsedForSvmTraining // } }, // --- }, watch: { // filterImageProcessed() { // if (this.isVisible) { // this.redrawPoints(this.xScaleZoomed) // } // }, filterIsDay() { if (this.isVisible) { this.redrawPoints(this.xScaleZoomed) Loading Loading @@ -334,11 +320,6 @@ export default { this.redrawPoints(this.xScaleZoomed) } }, // filterImageUsedForSvmTraining() { // if (this.isVisible) { // this.redrawPoints(this.xScaleZoomed) // } // }, activeImageName(imageName) { if (imageName) { this.$activePoint.attr('visibility', 'visible') Loading Loading @@ -395,7 +376,7 @@ export default { } this.redrawPoints(this.xScaleZoomed) } } }, }, methods: { handleResize({ width }) { Loading Loading @@ -487,22 +468,12 @@ export default { g.attr( 'transform', `translate(0,${this.height - this.margin.bottom})` ).call( d3 .axisBottom(x) .ticks(10) .tickSizeOuter(0) ) ).call(d3.axisBottom(x).ticks(10).tickSizeOuter(0)) }, yAxis(g, y) { g.attr('transform', `translate(${this.margin.left},0)`) .call( d3 .axisLeft(y) .ticks(5) .tickSizeOuter(0) ) .call(g => .call(d3.axisLeft(y).ticks(5).tickSizeOuter(0)) .call((g) => g .select('.tick:last-of-type text') .clone() Loading Loading @@ -530,8 +501,8 @@ export default { opacity = 0.2 } const timestamp = this.chartData[imageName].dateTime const snowHeight = this.chartData[imageName].sticks[this.stickID] .snowHeight const snowHeight = this.chartData[imageName].sticks[this.stickID].snowHeight const type = this.stickType(imageName) if (type.type === 'cross') { this.drawCross( Loading Loading @@ -665,8 +636,8 @@ export default { for (const image in this.chartData) { if (Object.hasOwnProperty.call(this.chartData, image)) { const timestamp = this.chartData[image].dateTime const snowHeightAverage = this.chartData[image].sticks[this.stickID] .snowHeightAverage const snowHeightAverage = this.chartData[image].sticks[this.stickID].snowHeightAverage if (lastTimestamp != null) { this.drawLine( context, Loading Loading @@ -732,10 +703,7 @@ export default { this.$hoveredPoint.attr('visibility', 'visible') this.$hoveredPoint .select('circle') .attr('cx', px) .attr('cy', py) this.$hoveredPoint.select('circle').attr('cx', px).attr('cy', py) this.$hoveredPoint .select('line') Loading Loading @@ -763,10 +731,7 @@ export default { } this.$activePoint.attr('visibility', 'visible') this.$activePoint .select('circle') .attr('cx', px) .attr('cy', py) this.$activePoint.select('circle').attr('cx', px).attr('cy', py) this.$activePoint .select('line') Loading @@ -774,7 +739,7 @@ export default { .attr('y1', Math.min(py + this.datapointRadius, this.rangeY[0])) .attr('x2', px) .attr('y2', this.rangeY[0]) } }, }, mounted() { this.$chart Loading @@ -784,7 +749,7 @@ export default { .on('click', this.clicked) .on('mousedown', () => this.$hoveredPoint.attr('visibility', 'hidden')) .on('mouseup', () => this.$hoveredPoint.attr('visibility', 'visible')) .on('wheel', event => { .on('wheel', (event) => { this.$hoveredPoint.attr('visibility', 'hidden') // Prevent scrolling the whole page when using mouse wheel on chart. if ( Loading @@ -799,7 +764,7 @@ export default { this.$yAxis.call(this.yAxis, this.yScale) this.width = this.$chart.node().clientWidth } }, } </script> Loading
src/store/actions.js +41 −14 Original line number Diff line number Diff line import DatasetService from '@/services/dataset-service' import SunCalc from 'suncalc' import Vue from 'vue' import gradientBackground from './gradient-background' const _sendPostRequest = (state, commit, webCmd, isCommit = false) => { Loading Loading @@ -121,7 +122,12 @@ export default { dispatch('buildImageChronology', cameraID) for (const imageName of Object.keys(data)) { for (const stickID of Object.keys(data[imageName].sticks)) { dispatch('updateSnowHeightAverage', { cameraID, imageName, stickID }) dispatch('updateSnowHeightAverage', { cameraID, imageName, stickID, usingMutations: false, }) } } }) Loading @@ -146,19 +152,32 @@ export default { updateSnowHeightAverage( { commit, state, getters }, { cameraID, imageName, stickID } { cameraID, imageName, stickID, usingMutations = true } ) { // Due to unreasonable number of mutations invoked at the start // (snow height average is computed for every image in the beginning), // I added the "usingMutations" flag. It is true by default. // The only time it's reasonable to switch it off is at the beginning, as mentioned. // If the stick is not visible, but there was snow in the picture, don't trust the average and therefore don't measure it. if ( !state.data[cameraID][imageName].sticks[stickID].visible && state.data[cameraID][imageName].weatherConditions === 1 ) { commit('UPDATE_SNOW_HEIGHT_AVERAGE', { if (usingMutations) { commit('SET_SNOW_HEIGHT_AVERAGE', { cameraID, imageName, stickID, average: -1, }) } else { Vue.set( state.data[cameraID][imageName].sticks[stickID], 'snowHeightAverage', -1 ) } return } Loading Loading @@ -188,12 +207,20 @@ export default { } } const average = count === 0 ? 0 : heightSum / count commit('UPDATE_SNOW_HEIGHT_AVERAGE', { if (usingMutations) { commit('SET_SNOW_HEIGHT_AVERAGE', { cameraID, imageName, stickID, average, }) } else { Vue.set( state.data[cameraID][imageName].sticks[stickID], 'snowHeightAverage', average ) } }, setImageDateTime({ state, commit }, { cameraID, imageName, dateTimeString }) { Loading
src/store/index.js +13 −18 Original line number Diff line number Diff line Loading @@ -15,16 +15,11 @@ export default new Vuex.Store({ //Format: stickID: { // x: number, // y: number, // positionMean: { // cameraID: { // top: [number, number], // bottom: [number, number], // } //} // statusGUI: 'full' | 'compact' | 'minimized', // lengthCm: number, // labels: {cameraID: 'label', cameraID: 'label'}, // primaryCamera: 'cameraID'} // primaryCamera: 'cameraID' //} cameras: {}, // Format: cameraID: {x: number, y: number, statusGUI: 'full' | 'minimized'} timespan: { start: new Date(), end: new Date() }, Loading Loading @@ -88,23 +83,23 @@ export default new Vuex.Store({ astronomicalTwilight: '#ecd7db', nauticalTwilight: '#f9e4d5', civilTwilight: '#fef1e0', day: '#fffff4' day: '#fffff4', }, controls: { showDaysGradient: true, showImageDialog: false, showFilters: false, showLegend: false, showHelpDialog: true showHelpDialog: true, }, zoomState: { selection: [0, 1], zoomingID: null zoomingID: null, // TODO: Add functions to manipulate this object into the object itself. }, redrawTrigger: false, // Value is not important, the change of state will trigger chart redrawing. server: { hasPendingChanges: false hasPendingChanges: false, }, filters: { imageProcessed: 2, Loading @@ -116,10 +111,10 @@ export default new Vuex.Store({ imageSticksEdited: 2, imageApproved: 2, imageDiscarded: 2, imageUsedForSvmTraining: 2 } imageUsedForSvmTraining: 2, }, }, mutations, actions, getters getters, })
src/store/mutations.js +4 −5 Original line number Diff line number Diff line Loading @@ -26,9 +26,8 @@ export default { state, { cameraID, imageName, recipCameraID, closestRecipImageName } ) { state.data[cameraID][imageName].reciprocalImageName[ recipCameraID ] = closestRecipImageName state.data[cameraID][imageName].reciprocalImageName[recipCameraID] = closestRecipImageName }, SET_STICK_SNOW_HEIGHT(state, { cameraID, imageName, stickID, snowHeight }) { // Vue.set( Loading Loading @@ -107,7 +106,7 @@ export default { SET_FILTER(state, { filterKind, value }) { state.filters[filterKind] = value }, UPDATE_SNOW_HEIGHT_AVERAGE(state, { cameraID, imageName, stickID, average }) { SET_SNOW_HEIGHT_AVERAGE(state, { cameraID, imageName, stickID, average }) { Vue.set( state.data[cameraID][imageName].sticks[stickID], 'snowHeightAverage', Loading @@ -116,5 +115,5 @@ export default { }, SET_SERVER_PENDING_CHANGES(state, value) { state.server.hasPendingChanges = value } }, }