Mercurial > gemma
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/TimeSlider.vue Thu Feb 27 09:18:17 2020 +0100 @@ -0,0 +1,172 @@ +<template> + <div + id="slider" + :class="[ + 'd-flex box ui-element rounded bg-white mw-100 flex-row', + { expand: showTimeSlider } + ]" + > + <div + id="sliderContainer" + class="d-flex sliderContainer" + style="width: 98%;" + ></div> + <div @click="close" class="d-flex box-control mr-0" style="width: 2%;"> + <font-awesome-icon icon="times"></font-awesome-icon> + </div> + </div> +</template> +<style lang="sass"> +#slider + position: absolute + bottom: 0 + width: 100% + &.expand + max-height: 100%; + max-width: 100%; + margin: 0 +</style> +<script> +/* This is Free Software under GNU Affero General Public License v >= 3.0 + * without warranty, see README.md and license for details. + * + * SPDX-License-Identifier: AGPL-3.0-or-later + * License-Filename: LICENSES/AGPL-3.0.txt + * + * Copyright (C) 2020 by via donau + * – Österreichische Wasserstraßen-Gesellschaft mbH + * Software engineering by Intevation GmbH + * + * Author(s): + * Fadi Abbud <fadiabbud@intevation.de> + */ +import { mapState } from "vuex"; +import * as d3 from "d3"; +export default { + name: "timeslider", + data() { + return { + selectedTime: new Date("2020-01-04"), + newX: null + }; + }, + computed: { + ...mapState("application", ["showTimeSlider"]) + }, + methods: { + close() { + this.$store.commit("application/showTimeSlider", false); + }, + createSlider() { + const element = document.getElementById("sliderContainer"); + const svgWidth = element ? element.clientWidth : 0, + svgHeight = 40, + marginTop = 20, + marginLeft = 0; + + this.newX = this.getScale(); + let svg = d3 + .select(".sliderContainer") + .append("svg") + .attr("width", svgWidth) + .attr("height", svgHeight); + + // zoom event + let zoom = d3 + .zoom() + .scaleExtent([0, Infinity]) + .translateExtent([[0, 0], [svgWidth, svgHeight]]) + .extent([[0, 0], [(svgWidth, svgHeight)]]) + .on("zoom", this.zoomed); + + svg + .append("g") + .attr("class", "axis--x") + .attr("transform", `translate(${marginLeft}, ${marginTop})`) + .call( + d3.axisBottom(this.newX).ticks(12) + //.tickFormat(dFormat) + ); + + // create rectanlge on the slider area to capture mouse events + const eventRect = svg + .append("rect") + .attr("id", "zoom") + .attr("class", "zoom") + .attr("width", svgWidth) + .attr("height", svgHeight) + .attr("fill", "white") + .attr("opacity", 0.2) + .on("mouseover", () => { + svg.select(".zoom").attr("cursor", "move"); + }); + eventRect.call(zoom).on("click", this.onClick); + + const toIsoDate = d => { + return d.toISOString(); + }; + + let drag = d3 + .drag() + .on("start", () => { + d3.select(".line") + .raise() + .classed("active", true); + }) + .on("drag", this.onDrag) + .on("end", () => { + d3.select(".line").classed("active", false); + }); + + // Create cursor to indicate to the selected time + svg + .append("rect") + .attr("class", "line") + .attr("id", "scrubber") + .attr("x", this.newX(d3.isoParse(toIsoDate(this.selectedTime)))) + .attr("y", 0) + .attr("width", 2) + .attr("height", svgHeight) + .attr("stroke", "#17a2b8") + .attr("stroke-width", 2) + .attr("opacity", 0.6) + .on("mouseover", () => { + svg.select(".line").attr("cursor", "e-resize"); + }) + .call(drag); + }, + getScale() { + return d3 + .scaleTime() + .range([0, document.getElementById("sliderContainer").clientWidth || 0]) + .domain([ + d3.isoParse(new Date("2020-01-01")), + d3.isoParse(new Date("2020-03-01")) + ]); + }, + zoomed() { + let scale = this.getScale(); + this.newX = d3.event.transform.rescaleX(scale); + d3.select(".axis--x").call( + d3.axisBottom(this.newX).ticks(12) + //.tickFormat(dFormat) + ); + d3.select(".line").attr("x", this.newX(d3.isoParse(this.selectedTime))); + }, + onClick() { + // Extract the click location + let point = d3.mouse(document.getElementById("zoom")), + p = { x: point[0], y: point[1] }; + d3.select(".line").attr("x", p.x); + this.selectedTime = d3.isoParse(this.newX.invert(p.x + 2)); + }, + onDrag() { + this.selectedTime = d3.isoParse(this.newX.invert(d3.event.x + 2)); + d3.select(".line").attr("x", d3.event.x); + } + }, + mounted() { + setTimeout(this.createSlider, 150); + } +}; +</script>