Skip to content

Commit

Permalink
Merge pull request #28 from brenzy/feature/undo-redo-stack
Browse files Browse the repository at this point in the history
Add an undo/redo stack
  • Loading branch information
brenzy authored May 4, 2021
2 parents 2b7baa2 + 90fe6ca commit 1756c41
Show file tree
Hide file tree
Showing 16 changed files with 354 additions and 105 deletions.
20 changes: 4 additions & 16 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
- input validation
- browser compatibility check
- accept more than one file type (fit, tcx, kml)
- try some different UI alternatives for less scrolling
- editing the route and elevation from the route map
- mini elevation chart on the route map
- draggable points on the elevation charts
- undo/redo stack
- charts code clean-up to get rid of repeated code
- Vue 3 migration
- typescript
- snip the route
- reverse the route
- zoom and pan on the graphs
- zoom to route on the map
## [1.8.0] - 2021-05-04
### Added
- added an undo/redo stack
- added an overlay while loading or processing

## [1.7.1] - 2021-01-17
### Changed
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ This is a work in progress...
- [ ] editing the route and elevation from the route map
- [ ] mini elevation chart on the route map
- [ ] draggable points on the elevation charts
- [ ] undo/redo stack
- [ ] edit and delete on the undo/redo stack
- [ ] charts code clean-up to get rid of repeated code
- [ ] Vue 3 migration
- [ ] typescript
- [ ] snip the route
- [ ] reverse the route
- [ ] zoom and pan on the graphs
- [ ] zoom to route on the map
- [ ] web worker for long-running processes

## Project setup
```
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"kalmanjs": "^1.1.0",
"leaflet": "^1.6.0",
"ml-savitzky-golay-generalized": "^1.1.1",
"ramda": "^0.27.1",
"vue": "^2.6.10",
"vue-router": "^3.0.3",
"vuetify": "^2.3.8",
Expand Down
14 changes: 14 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,27 @@
<router-view/>
</keep-alive>
</v-main>
<v-overlay :value="isProcessing" opacity=".35">
<div class="wait-text">PROCESSING...</div>
</v-overlay>
</v-app>
</template>

<script>
import Toolbar from './components/Toolbar';
import {mapState} from 'vuex';
export default {
name: 'App',
components: {Toolbar},
data: () => ({
//
}),
computed: {
...mapState(['isSmoothingInProgress']),
...mapState({
isProcessing: state => state.isLoading || state.isSmoothingInProgress,
}),
}
};
</script>

Expand All @@ -31,4 +41,8 @@ export default {
html {
overflow-y: auto;
}
.wait-text {
font-size: 60px;
color: white;
}
</style>
21 changes: 15 additions & 6 deletions src/components/Charts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
<v-btn :value="graphTypes.SLOPE_DISTANCE">Slope Chart</v-btn>
<v-btn :value="graphTypes.ELEVATION_PROFILE">Elevation Profile</v-btn>
</v-btn-toggle>
<DistanceChart
v-if="isActive"
:graph-type="graphType"
:color-scale="colorScale"
:graph-units="graphUnits"
></DistanceChart>
<div class="distance-chart">
<DistanceChart
v-if="isActive"
:graph-type="graphType"
:color-scale="colorScale"
:graph-units="graphUnits"
:selection="selection"
></DistanceChart>
</div>
<Legend
:graph-type="graphType"
:color-scale="colorScale"
Expand All @@ -38,6 +41,7 @@
import * as d3 from 'd3';
import Legend from './Legend';
import {UnitType} from '@/components/chartModel';
import {mapState} from 'vuex';
export default {
name: 'Charts',
Expand All @@ -49,6 +53,9 @@
colorScale: null,
graphUnits: UnitType.METRIC
}),
computed: {
...mapState(['selection']),
},
mounted() {
if (localStorage.graphUnits) {
this.graphUnits = localStorage.graphUnits === UnitType.IMPERIAL ? UnitType.IMPERIAL : UnitType.METRIC ;
Expand Down Expand Up @@ -77,4 +84,6 @@
margin: 20px 20px 0 20px
.chart-type-group
margin: 0 0 20px 20px
.distance-chart
height: 500px
</style>
45 changes: 26 additions & 19 deletions src/components/DistanceChart.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<template>
<div>
<div id="chart">
</div>
<div id="chart">
</div>
</template>

Expand All @@ -11,13 +9,13 @@
import {GraphType, LineTypes, UnitType} from './chartModel';
import {convertDistance, convertElevation, kmToMiles, metresToFeet} from '@/utilities/unitConversion';
// noinspection JSUnusedGlobalSymbols
export default {
name: 'DistanceChart',
props: {
graphType: String,
colorScale: Function,
graphUnits: UnitType
graphUnits: UnitType,
selection: Array
},
data: () => ({
defaultDistance: 100000,
Expand Down Expand Up @@ -49,8 +47,11 @@
},
beforeDestroy() {
window.removeEventListener('resize', this.resize);
if (this.tooltip) {
this.tooltip.remove();
}
},
computed: mapState(['rawValues', 'selection', 'totalDistance', 'smoothedValues']),
computed: mapState(['rawValues', 'totalDistance', 'smoothedValues']),
watch: {
rawValues(newValue) {
if (!this.svg) {
Expand Down Expand Up @@ -99,7 +100,7 @@
if (!this.svg) {
return;
}
this.onSelectionUpdate(newValue);
this.redrawSelection(newValue);
}
},
methods: {
Expand Down Expand Up @@ -163,6 +164,8 @@
.attr('width', this.width)
.attr('y', -this.margin.top)
.attr('height', this.height + this.margin.top + this.margin.bottom); // Leave some room at the top and bottom
this.redrawSelection(this.selection);
},
draw() {
this.focus.select('.x.axis').call(this.xAxis);
Expand Down Expand Up @@ -191,12 +194,11 @@
+ ' ' + this.xScale(datum.previous.totalDistance) + ',' + this.yScale(this.yScale.domain()[0]);
});
},
onSelectionUpdate(selection) {
if (!selection) {
return;
redrawSelection(selection) {
if (selection) {
this.xScale.domain(selection);
this.xScaleImperial.domain(selection.map(distance => kmToMiles(distance)));
}
this.xScale.domain(selection);
this.xScaleImperial.domain(selection.map(distance => kmToMiles(distance)));
this.focus.select('.x.axis').call(this.xAxis);
this.focus.selectAll('path.elevation').attr('d', this.elevationLine);
this.focus.selectAll('path.slope').attr('d', this.slopeLine);
Expand Down Expand Up @@ -487,11 +489,17 @@
const extents = this.getExtents();
this.xScale = d3.scaleLinear()
.range([0, this.width])
.domain(extents.xExtent);
.range([0, this.width]);
this.xScaleImperial = d3.scaleLinear()
.range([0, this.width])
.domain(extents.xExtent.map(distance => kmToMiles(distance)));
.range([0, this.width]);
if (this.selection) {
this.xScale.domain(this.selection);
this.xScaleImperial.domain(this.selection.map(distance => kmToMiles(distance)));
} else {
this.xScale.domain(extents.xExtent);
this.xScaleImperial.domain(extents.xExtent.map(distance => kmToMiles(distance)));
}
this.yScale = d3.scaleLinear()
.range([this.height, 0])
Expand Down Expand Up @@ -543,8 +551,7 @@
this.focus.append('g')
.attr('clip-path', 'url(#clip)');
// Get the position of the graph so we can set the
// the offset of the tooltip
// Get the position of the graph element so we can set the offset of the tooltip
this.graphElement = this.svg.node();
this.tooltip = d3.select('body').append('div')
Expand Down Expand Up @@ -586,7 +593,7 @@
#chart
font: 10px sans-serif
width: 100%
height: 500px
height: 100%
.axis path,
.axis line
Expand Down
17 changes: 5 additions & 12 deletions src/components/Legend.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,13 @@
colorScale: Function
},
data: () => ({
graphTypes: GraphType,
formattedRawAverage: '',
formattedSmoothedAverage: ''
graphTypes: GraphType
}),
computed: {
...mapState(['rawAverageSlope', 'smoothedAverageSlope']),
},
watch: {
rawAverageSlope() {
this.formattedRawAverage = this.rawAverageSlope ? `${this.rawAverageSlope}%` : '';
},
smoothedAverageSlope() {
this.formattedSmoothedAverage = this.smoothedAverageSlope ? `${this.smoothedAverageSlope}%` : '';
}
...mapState({
formattedRawAverage: state => state.rawAverageSlope ? `${state.rawAverageSlope}%` : '',
formattedSmoothedAverage: state => state.smoothedAverageSlope ? `${state.smoothedAverageSlope}%` : '',
}),
},
mounted() {
this.$nextTick(() => {
Expand Down
11 changes: 8 additions & 3 deletions src/components/SelectionChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {mapState} from 'vuex';
import {GraphType, LineTypes, UnitType} from './chartModel';
import store from '../store/store';
import {convertElevation, kmToMiles, metresToFeet} from '@/utilities/unitConversion';
import {equals} from 'ramda';
export default {
name: 'SelectionChart',
Expand Down Expand Up @@ -220,7 +221,11 @@ export default {
brushed() {
if (d3.event && d3.event.selection) {
const newSelection = d3.event.selection.map(this.miniXScale.invert);
store.dispatch('select', newSelection);
// This gets called on a resize to redraw the brush, so we need to check
// if the selection has actually changed before updating the selection
if (!equals(this.selection, newSelection)) {
store.dispatch('select', newSelection);
}
this.drawSelectionHandles(newSelection);
}
},
Expand Down Expand Up @@ -429,7 +434,6 @@ export default {
})
.curve(d3.curveStepBefore);
store.dispatch('select', this.miniXScale.domain());
this.brush = d3
.brushX()
.extent([
Expand Down Expand Up @@ -465,7 +469,8 @@ export default {
.attr('cursor', 'ew-resize')
.attr('d', triangleShape);
this.gBrush.call(this.brush.move, this.xScale.range());
const selection = (this.selection === null) ? this.xScale.range() : this.selection.map(this.miniXScale);
this.gBrush.call(this.brush.move, selection);
}
}
};
Expand Down
1 change: 1 addition & 0 deletions src/components/Toolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<v-app-bar app dark color="primary">
<v-toolbar-items>
<v-btn text to="/">GPX Smoother Version {{ appVersion }}</v-btn>
<v-btn text to="/history">Smoothing History</v-btn>
<v-btn text to="/route-map">Route Map</v-btn>
</v-toolbar-items>
<v-spacer/>
Expand Down
6 changes: 6 additions & 0 deletions src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Vue from 'vue';
import Router from 'vue-router';
import GpxSmoother from '@/views/GpxSmoother';
import RouteMap from '@/views/RouteMap';
import History from '@/views/History';

Vue.use(Router);

Expand All @@ -17,6 +18,11 @@ export default new Router({
name: 'route-map',
component: RouteMap
},
{
path: '/history',
name: 'history',
component: History
},
{
path: '/about',
name: 'about',
Expand Down
Loading

0 comments on commit 1756c41

Please sign in to comment.