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