comparison client/src/components/gauge/Waterlevel.vue @ 4155:552ea22ed266 improvepdf

merge default into improvepdf
author Thomas Junk <thomas.junk@intevation.de>
date Fri, 02 Aug 2019 13:30:29 +0200
parents 4d7569cca5e6 d54d86d27e82
children 92c2f93fef3c
comparison
equal deleted inserted replaced
4140:4d7569cca5e6 4155:552ea22ed266
104 import * as d3Base from "d3"; 104 import * as d3Base from "d3";
105 import { lineChunked } from "d3-line-chunked"; 105 import { lineChunked } from "d3-line-chunked";
106 import { endOfDay } from "date-fns"; 106 import { endOfDay } from "date-fns";
107 import debounce from "debounce"; 107 import debounce from "debounce";
108 import { saveAs } from "file-saver"; 108 import { saveAs } from "file-saver";
109 import { diagram, pdfgen, templateLoader } from "@/lib/mixins"; 109 import { diagram, pdfgen, templateLoader, refwaterlevels } from "@/lib/mixins";
110 import { HTTP } from "@/lib/http"; 110 import { HTTP } from "@/lib/http";
111 import { displayError } from "@/lib/errors"; 111 import { displayError } from "@/lib/errors";
112 import { defaultDiagramTemplate } from "@/lib/DefaultDiagramTemplate"; 112 import { defaultDiagramTemplate } from "@/lib/DefaultDiagramTemplate";
113 // we should load only d3 modules we need but for now we'll go with the lazy way 113 // we should load only d3 modules we need but for now we'll go with the lazy way
114 // https://www.giacomodebidda.com/how-to-import-d3-plugins-with-webpack/ 114 // https://www.giacomodebidda.com/how-to-import-d3-plugins-with-webpack/
115 // d3-line-chunked plugin: https://github.com/pbeshai/d3-line-chunked 115 // d3-line-chunked plugin: https://github.com/pbeshai/d3-line-chunked
116 const d3 = Object.assign(d3Base, { lineChunked }); 116 const d3 = Object.assign(d3Base, { lineChunked });
117 117
118 export default { 118 export default {
119 mixins: [diagram, pdfgen, templateLoader], 119 mixins: [diagram, pdfgen, templateLoader, refwaterlevels],
120 components: { 120 components: {
121 DiagramLegend: () => import("@/components/DiagramLegend") 121 DiagramLegend: () => import("@/components/DiagramLegend")
122 }, 122 },
123 data() { 123 data() {
124 return { 124 return {
463 .attr("stroke-width", 1) 463 .attr("stroke-width", 1)
464 .attr("fill", "none") 464 .attr("fill", "none")
465 .attr("clip-path", "url(#waterlevel-clip)"); 465 .attr("clip-path", "url(#waterlevel-clip)");
466 svg.selectAll(".hdc-line").attr("stroke", "red"); 466 svg.selectAll(".hdc-line").attr("stroke", "red");
467 svg.selectAll(".ldc-line").attr("stroke", "green"); 467 svg.selectAll(".ldc-line").attr("stroke", "green");
468
468 svg.selectAll(".mw-line").attr("stroke", "rgb(128,128,128)"); 469 svg.selectAll(".mw-line").attr("stroke", "rgb(128,128,128)");
469 svg.selectAll(".rn-line").attr("stroke", "rgb(128,128,128)"); 470 svg.selectAll(".rn-line").attr("stroke", "rgb(128,128,128)");
470 svg 471 svg
471 .selectAll(".ref-waterlevel-label") 472 .selectAll(".ref-waterlevel-label")
472 .style("font-size", "10px") 473 .style("font-size", "10px")
557 .selectAll(".chart-tooltip text") 558 .selectAll(".chart-tooltip text")
558 .attr("fill", "666") 559 .attr("fill", "666")
559 .style("font-size", "0.8em"); 560 .style("font-size", "0.8em");
560 }, 561 },
561 getExtent(refWaterLevels) { 562 getExtent(refWaterLevels) {
563 let rest;
564 if (refWaterLevels) {
565 // set min/max values for the waterlevel axis
566 // including HDC (+ 1/8 HDC-LDC) and LDC (- 1/4 HDC-LDC)
567 const { LDC, HDC } = this.determineLDCHDC(refWaterLevels);
568 rest = [
569 {
570 waterlevel: HDC + (HDC - LDC) / 8
571 },
572 {
573 waterlevel: Math.max(LDC - (HDC - LDC) / 4, 0)
574 }
575 ];
576 } else {
577 rest = [];
578 }
562 return { 579 return {
563 // set min/max values for the date axis 580 // set min/max values for the date axis
564 date: [ 581 date: [
565 this.waterlevels[0].date, 582 this.waterlevels[0].date,
566 endOfDay(this.waterlevels[this.waterlevels.length - 1].date) 583 endOfDay(this.waterlevels[this.waterlevels.length - 1].date)
567 ], 584 ],
568 // set min/max values for the waterlevel axis 585 waterlevel: d3.extent([...this.waterlevels, ...rest], d => d.waterlevel)
569 // including HDC (+ 1/8 HDC-LDC) and LDC (- 1/4 HDC-LDC)
570 waterlevel: d3.extent(
571 [
572 ...this.waterlevels,
573 {
574 waterlevel:
575 refWaterLevels.HDC +
576 (refWaterLevels.HDC - refWaterLevels.LDC) / 8
577 },
578 {
579 waterlevel: Math.max(
580 refWaterLevels.LDC -
581 (refWaterLevels.HDC - refWaterLevels.LDC) / 4,
582 0
583 )
584 }
585 ],
586 d => d.waterlevel
587 )
588 }; 586 };
589 }, 587 },
590 getScale({ dimensions, extent }) { 588 getScale({ dimensions, extent }) {
591 // scaling helpers to convert real world values into pixels 589 // scaling helpers to convert real world values into pixels
592 const x = d3.scaleTime().range([0, dimensions.width]); 590 const x = d3.scaleTime().range([0, dimensions.width]);
593 const y = d3.scaleLinear().range([dimensions.mainHeight, 0]); 591 const y = d3.scaleLinear().range([dimensions.mainHeight, 0]);
594 const x2 = d3.scaleTime().range([0, dimensions.width]); 592 const x2 = d3.scaleTime().range([0, dimensions.width]);
595 const y2 = d3.scaleLinear().range([dimensions.navHeight, 0]); 593 const y2 = d3.scaleLinear().range([dimensions.navHeight, 0]);
596 594 const [lo, hi] = extent.waterlevel;
597 // setting the min and max values for the diagram axes 595 // setting the min and max values for the diagram axes
596 const dy = Math.ceil(0.15 * (hi - lo));
598 x.domain(d3.extent(extent.date)); 597 x.domain(d3.extent(extent.date));
599 y.domain(extent.waterlevel); 598 y.domain([lo - dy, hi + dy]);
600 x2.domain(x.domain()); 599 x2.domain(x.domain());
601 y2.domain(y.domain()); 600 y2.domain(y.domain());
602 601
603 return { x, y, x2, y2 }; 602 return { x, y, x2, y2 };
604 }, 603 },
699 .attr("class", "line") 698 .attr("class", "line")
700 .datum(this.waterlevels) 699 .datum(this.waterlevels)
701 .call(lineChunked); 700 .call(lineChunked);
702 }, 701 },
703 drawNowLines({ scale, extent, diagram, navigation }) { 702 drawNowLines({ scale, extent, diagram, navigation }) {
703 const [lo, hi] = extent.waterlevel;
704 const dy = Math.ceil(0.15 * (hi - lo));
704 const nowLine = d3 705 const nowLine = d3
705 .line() 706 .line()
706 .x(d => scale.x(d.x)) 707 .x(d => scale.x(d.x))
707 .y(d => scale.y(d.y)); 708 .y(d => scale.y(d.y));
708 709
709 const nowLabel = selection => { 710 const nowLabel = selection => {
710 selection.attr( 711 selection.attr(
711 "transform", 712 "transform",
712 `translate(${scale.x(new Date())}, ${scale.y( 713 `translate(${scale.x(new Date())}, ${scale.y(hi + dy * 0.4)})`
713 extent.waterlevel[1] - 16
714 )})`
715 ); 714 );
716 }; 715 };
717 716
718 // draw in main 717 // draw in main
719 diagram 718 diagram
720 .append("path") 719 .append("path")
721 .datum([ 720 .datum([
722 { x: new Date(), y: extent.waterlevel[0] }, 721 { x: new Date(), y: lo - dy },
723 { x: new Date(), y: extent.waterlevel[1] - 20 } 722 { x: new Date(), y: hi + dy * 0.4 }
724 ]) 723 ])
725 .attr("class", "now-line") 724 .attr("class", "now-line")
726 .attr("d", nowLine); 725 .attr("d", nowLine);
727 diagram // label 726 diagram // label
728 .append("text") 727 .append("text")
732 .call(nowLabel); 731 .call(nowLabel);
733 732
734 // draw in nav 733 // draw in nav
735 navigation 734 navigation
736 .append("path") 735 .append("path")
737 .datum([ 736 .datum([{ x: new Date(), y: hi + dy }, { x: new Date(), y: lo - dy }])
738 { x: new Date(), y: extent.waterlevel[0] },
739 { x: new Date(), y: extent.waterlevel[1] - 20 }
740 ])
741 .attr("class", "now-line") 737 .attr("class", "now-line")
742 .attr( 738 .attr(
743 "d", 739 "d",
744 d3 740 d3
745 .line() 741 .line()
776 return () => { 772 return () => {
777 diagram.select(".prediction-area").attr("d", predictionArea()); 773 diagram.select(".prediction-area").attr("d", predictionArea());
778 }; 774 };
779 }, 775 },
780 drawRefLines({ refWaterLevels, diagram, scale, dimensions, extent }) { 776 drawRefLines({ refWaterLevels, diagram, scale, dimensions, extent }) {
781 // filling area between HDC and LDC 777 if (refWaterLevels) {
782 diagram 778 const { LDC, HDC } = this.determineLDCHDC(refWaterLevels);
783 .append("rect") 779 // filling area between HDC and LDC if both of them are available
784 .attr("class", "hdc-ldc-area") 780 if (LDC && HDC) {
785 .attr("x", 0) 781 diagram
786 .attr("y", scale.y(refWaterLevels.HDC)) 782 .append("rect")
787 .attr("width", dimensions.width) 783 .attr("class", "hdc-ldc-area")
788 .attr( 784 .attr("x", 0)
789 "height", 785 .attr("y", scale.y(HDC))
790 scale.y(refWaterLevels.LDC) - scale.y(refWaterLevels.HDC) 786 .attr("width", dimensions.width)
791 ); 787 .attr("height", refWaterLevels ? scale.y(LDC) - scale.y(HDC) : 0);
788 }
789 }
792 790
793 const refWaterlevelLine = d3 791 const refWaterlevelLine = d3
794 .line() 792 .line()
795 .x(d => scale.x(d.x)) 793 .x(d => scale.x(d.x))
796 .y(d => scale.y(d.y)); 794 .y(d => scale.y(d.y));
795
796 const levelStyle = name => {
797 if (/HDC/.test(name)) return "hdc-line";
798 if (/LDC/.test(name)) return "ldc-line";
799 return `${name.toLowerCase()}-line`;
800 };
797 801
798 for (let ref in refWaterLevels) { 802 for (let ref in refWaterLevels) {
799 if (refWaterLevels[ref]) { 803 if (refWaterLevels[ref]) {
800 diagram 804 diagram
801 .append("path") 805 .append("path")
802 .datum([ 806 .datum([
803 { x: 0, y: refWaterLevels[ref] }, 807 { x: 0, y: refWaterLevels[ref] },
804 { x: extent.date[1], y: refWaterLevels[ref] } 808 { x: extent.date[1], y: refWaterLevels[ref] }
805 ]) 809 ])
806 .attr("class", ref.toLowerCase() + "-line") 810 .attr("class", levelStyle(ref))
807 .attr("d", refWaterlevelLine); 811 .attr("d", refWaterlevelLine);
808 diagram // label 812 diagram // label
809 .append("rect") 813 .append("rect")
810 .attr("class", "ref-waterlevel-label-background") 814 .attr("class", "ref-waterlevel-label-background")
811 .attr("x", 1) 815 .attr("x", 1)
953 diagram 957 diagram
954 .append("g") 958 .append("g")
955 .attr("class", "chart-dots") 959 .attr("class", "chart-dots")
956 .append("circle") 960 .append("circle")
957 .attr("class", "chart-dot") 961 .attr("class", "chart-dot")
962 .attr("opacity", 0)
958 .attr("r", 4); 963 .attr("r", 4);
959 964
960 // create container for the tooltip 965 // create container for the tooltip
961 const tooltip = diagram.append("g").attr("class", "chart-tooltip"); 966 const tooltip = diagram.append("g").attr("class", "chart-tooltip");
962 tooltip 967 tooltip