Mercurial > gemma
view 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 source
<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>