Mercurial > gemma
comparison client/src/components/TimeSlider.vue @ 5036:8f421cd3c746 time-sliding
client: Implemented first version of time-sliding
author | Fadi Abbud <fadi.abbud@intevation.de> |
---|---|
date | Thu, 27 Feb 2020 09:18:17 +0100 |
parents | |
children | 9d288d9b851b |
comparison
equal
deleted
inserted
replaced
4893:b65898de11ad | 5036:8f421cd3c746 |
---|---|
1 <template> | |
2 <div | |
3 id="slider" | |
4 :class="[ | |
5 'd-flex box ui-element rounded bg-white mw-100 flex-row', | |
6 { expand: showTimeSlider } | |
7 ]" | |
8 > | |
9 <div | |
10 id="sliderContainer" | |
11 class="d-flex sliderContainer" | |
12 style="width: 98%;" | |
13 ></div> | |
14 <div @click="close" class="d-flex box-control mr-0" style="width: 2%;"> | |
15 <font-awesome-icon icon="times"></font-awesome-icon> | |
16 </div> | |
17 </div> | |
18 </template> | |
19 <style lang="sass"> | |
20 #slider | |
21 position: absolute | |
22 bottom: 0 | |
23 width: 100% | |
24 &.expand | |
25 max-height: 100%; | |
26 max-width: 100%; | |
27 margin: 0 | |
28 </style> | |
29 <script> | |
30 /* This is Free Software under GNU Affero General Public License v >= 3.0 | |
31 * without warranty, see README.md and license for details. | |
32 * | |
33 * SPDX-License-Identifier: AGPL-3.0-or-later | |
34 * License-Filename: LICENSES/AGPL-3.0.txt | |
35 * | |
36 * Copyright (C) 2020 by via donau | |
37 * – Österreichische Wasserstraßen-Gesellschaft mbH | |
38 * Software engineering by Intevation GmbH | |
39 * | |
40 * Author(s): | |
41 * Fadi Abbud <fadiabbud@intevation.de> | |
42 */ | |
43 import { mapState } from "vuex"; | |
44 import * as d3 from "d3"; | |
45 export default { | |
46 name: "timeslider", | |
47 data() { | |
48 return { | |
49 selectedTime: new Date("2020-01-04"), | |
50 newX: null | |
51 }; | |
52 }, | |
53 computed: { | |
54 ...mapState("application", ["showTimeSlider"]) | |
55 }, | |
56 methods: { | |
57 close() { | |
58 this.$store.commit("application/showTimeSlider", false); | |
59 }, | |
60 createSlider() { | |
61 const element = document.getElementById("sliderContainer"); | |
62 const svgWidth = element ? element.clientWidth : 0, | |
63 svgHeight = 40, | |
64 marginTop = 20, | |
65 marginLeft = 0; | |
66 | |
67 this.newX = this.getScale(); | |
68 let svg = d3 | |
69 .select(".sliderContainer") | |
70 .append("svg") | |
71 .attr("width", svgWidth) | |
72 .attr("height", svgHeight); | |
73 | |
74 // zoom event | |
75 let zoom = d3 | |
76 .zoom() | |
77 .scaleExtent([0, Infinity]) | |
78 .translateExtent([[0, 0], [svgWidth, svgHeight]]) | |
79 .extent([[0, 0], [(svgWidth, svgHeight)]]) | |
80 .on("zoom", this.zoomed); | |
81 | |
82 svg | |
83 .append("g") | |
84 .attr("class", "axis--x") | |
85 .attr("transform", `translate(${marginLeft}, ${marginTop})`) | |
86 .call( | |
87 d3.axisBottom(this.newX).ticks(12) | |
88 //.tickFormat(dFormat) | |
89 ); | |
90 | |
91 // create rectanlge on the slider area to capture mouse events | |
92 const eventRect = svg | |
93 .append("rect") | |
94 .attr("id", "zoom") | |
95 .attr("class", "zoom") | |
96 .attr("width", svgWidth) | |
97 .attr("height", svgHeight) | |
98 .attr("fill", "white") | |
99 .attr("opacity", 0.2) | |
100 .on("mouseover", () => { | |
101 svg.select(".zoom").attr("cursor", "move"); | |
102 }); | |
103 eventRect.call(zoom).on("click", this.onClick); | |
104 | |
105 const toIsoDate = d => { | |
106 return d.toISOString(); | |
107 }; | |
108 | |
109 let drag = d3 | |
110 .drag() | |
111 .on("start", () => { | |
112 d3.select(".line") | |
113 .raise() | |
114 .classed("active", true); | |
115 }) | |
116 .on("drag", this.onDrag) | |
117 .on("end", () => { | |
118 d3.select(".line").classed("active", false); | |
119 }); | |
120 | |
121 // Create cursor to indicate to the selected time | |
122 svg | |
123 .append("rect") | |
124 .attr("class", "line") | |
125 .attr("id", "scrubber") | |
126 .attr("x", this.newX(d3.isoParse(toIsoDate(this.selectedTime)))) | |
127 .attr("y", 0) | |
128 .attr("width", 2) | |
129 .attr("height", svgHeight) | |
130 .attr("stroke", "#17a2b8") | |
131 .attr("stroke-width", 2) | |
132 .attr("opacity", 0.6) | |
133 .on("mouseover", () => { | |
134 svg.select(".line").attr("cursor", "e-resize"); | |
135 }) | |
136 .call(drag); | |
137 }, | |
138 getScale() { | |
139 return d3 | |
140 .scaleTime() | |
141 .range([0, document.getElementById("sliderContainer").clientWidth || 0]) | |
142 .domain([ | |
143 d3.isoParse(new Date("2020-01-01")), | |
144 d3.isoParse(new Date("2020-03-01")) | |
145 ]); | |
146 }, | |
147 zoomed() { | |
148 let scale = this.getScale(); | |
149 this.newX = d3.event.transform.rescaleX(scale); | |
150 d3.select(".axis--x").call( | |
151 d3.axisBottom(this.newX).ticks(12) | |
152 //.tickFormat(dFormat) | |
153 ); | |
154 d3.select(".line").attr("x", this.newX(d3.isoParse(this.selectedTime))); | |
155 }, | |
156 onClick() { | |
157 // Extract the click location | |
158 let point = d3.mouse(document.getElementById("zoom")), | |
159 p = { x: point[0], y: point[1] }; | |
160 d3.select(".line").attr("x", p.x); | |
161 this.selectedTime = d3.isoParse(this.newX.invert(p.x + 2)); | |
162 }, | |
163 onDrag() { | |
164 this.selectedTime = d3.isoParse(this.newX.invert(d3.event.x + 2)); | |
165 d3.select(".line").attr("x", d3.event.x); | |
166 } | |
167 }, | |
168 mounted() { | |
169 setTimeout(this.createSlider, 150); | |
170 } | |
171 }; | |
172 </script> |