changeset 3912:b7dfee369f2f

available_fairwaydepthLNWL: factor out sideeffects and render offscreen
author Thomas Junk <thomas.junk@intevation.de>
date Thu, 11 Jul 2019 11:29:24 +0200
parents e4e496ae7974
children 9ec50fd5c9fa
files client/src/components/fairway/AvailableFairwayDepthLNWL.vue
diffstat 1 files changed, 125 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/fairway/AvailableFairwayDepthLNWL.vue	Thu Jul 11 10:58:22 2019 +0200
+++ b/client/src/components/fairway/AvailableFairwayDepthLNWL.vue	Thu Jul 11 11:29:24 2019 +0200
@@ -76,12 +76,12 @@
 import { mapState } from "vuex";
 import svg2pdf from "svg2pdf.js";
 import filters from "@/lib/filters.js";
-import { diagram, pdfgen, templateLoader } from "@/lib/mixins";
+import { pdfgen, templateLoader } from "@/lib/mixins";
 import { HTTP } from "@/lib/http";
 import { displayError } from "@/lib/errors";
 
 export default {
-  mixins: [diagram, pdfgen, templateLoader],
+  mixins: [pdfgen, templateLoader],
   components: {
     DiagramLegend: () => import("@/components/DiagramLegend")
   },
@@ -94,9 +94,6 @@
       scalePaddingLeft: 50,
       scalePaddingRight: 30,
       paddingTop: 10,
-      diagram: null,
-      yScale: null,
-      dimensions: null,
       pdf: {
         doc: null,
         width: null,
@@ -233,24 +230,6 @@
     featureName() {
       if (this.selectedFairwayAvailabilityFeature == null) return "";
       return this.selectedFairwayAvailabilityFeature.properties.name;
-    },
-    widthPerItem() {
-      return Math.min(
-        (this.dimensions.width -
-          this.scalePaddingLeft -
-          this.scalePaddingRight) /
-          this.fwLNWLData.length,
-        180
-      );
-    },
-    ldcWidth() {
-      return this.widthPerItem * 0.3;
-    },
-    afdWidth() {
-      return this.widthPerItem * 0.5;
-    },
-    spaceBetween() {
-      return this.widthPerItem * 0.2;
     }
   },
   methods: {
@@ -300,28 +279,32 @@
     addDiagram(position, offset, width, height) {
       let x = offset.x,
         y = offset.y;
-
-      var svgElement = this.$refs.diagramContainer.firstElementChild;
-
-      // use default width,height if they are missing in the template definition
-      if (!width) {
-        width = this.templateData.properties.paperSize === "a3" ? 380 : 290;
-      }
-      if (!height) {
-        height = this.templateData.properties.paperSize === "a3" ? 130 : 100;
-      }
+      const svgWidth = this.millimeter2pixels(width, 80);
+      const svgHeight = this.millimeter2pixels(height, 80);
+      // draw the diagram in a separated html element to get the full size
+      const offScreen = document.querySelector("#offScreen");
+      offScreen.style.width = `${svgWidth}px`;
+      offScreen.style.height = `${svgHeight}px`;
+      this.renderTo({
+        element: offScreen,
+        dimensions: this.getDimensions({
+          svgWidth: svgWidth,
+          svgHeight: svgHeight
+        })
+      });
+      var svg = offScreen.querySelector("svg");
       if (["topright", "bottomright"].indexOf(position) !== -1) {
         x = this.pdf.width - offset.x - width;
       }
       if (["bottomright", "bottomleft"].indexOf(position) !== -1) {
         y = this.pdf.height - offset.y - height;
       }
-
-      svg2pdf(svgElement, this.pdf.doc, {
+      svg2pdf(svg, this.pdf.doc, {
         xOffset: x,
         yOffset: y,
-        scale: this.templateData.properties.paperSize === "a3" ? 0.45 : 0.18 // TODO depend on the size and aspect ration on paper
+        scale: 0.354
       });
+      offScreen.removeChild(svg);
     },
     addDiagramLegend(position, offset, color) {
       let x = offset.x,
@@ -361,50 +344,90 @@
     close() {
       this.$store.commit("application/paneSetup", "DEFAULT");
     },
+    getDimensions({ svgHeight, svgWidth }) {
+      const mainMargin = { top: 20, right: 20, bottom: 110, left: 200 };
+      const navMargin = {
+        top: svgHeight - mainMargin.top - 65,
+        right: 20,
+        bottom: 30,
+        left: 80
+      };
+      const width = Number(svgWidth) - mainMargin.left - mainMargin.right;
+      const mainHeight = Number(svgHeight) - mainMargin.top - mainMargin.bottom;
+      const navHeight = Number(svgHeight) - navMargin.top - navMargin.bottom;
+      return { width, mainHeight, navHeight, mainMargin, navMargin };
+    },
     drawDiagram() {
-      this.dimensions = this.getDimensions({
-        main: { top: 20, right: 20, bottom: 110, left: 200 }
+      const elem = document.querySelector("#" + this.containerId);
+      const svgWidth = elem != null ? elem.clientWidth : 0;
+      const svgHeight = elem != null ? elem.clientHeight : 0;
+      const dimensions = this.getDimensions({
+        svgHeight,
+        svgWidth
       });
-      this.yScale = d3
-        .scaleLinear()
-        .domain([0, 100])
-        .range([this.dimensions.mainHeight - 30, 0]);
       d3.select(".diagram-container svg").remove();
-      this.generateDiagramContainer();
-      this.drawScaleLabel();
-      this.drawScale();
-      this.drawBars();
-      this.drawTooltip();
+      this.renderTo({ element: ".diagram-container", dimensions });
     },
-    drawTooltip() {
-      this.diagram
+    drawTooltip(diagram) {
+      diagram
         .append("text")
         .text("")
         .attr("font-size", "0.8em")
         .attr("opacity", 0)
         .attr("id", "tooltip");
     },
-    generateDiagramContainer() {
+    renderTo({ element, dimensions }) {
       const diagram = d3
-        .select(".diagram-container")
+        .select(element)
         .append("svg")
-        .attr("width", this.dimensions.width)
-        .attr("height", this.dimensions.mainHeight);
-      this.diagram = diagram
-        .append("g")
-        .attr("transform", `translate(0 ${this.paddingTop})`);
+        .attr("width", dimensions.width)
+        .attr("height", dimensions.mainHeight);
+      diagram.append("g").attr("transform", `translate(0 ${this.paddingTop})`);
+      const yScale = d3
+        .scaleLinear()
+        .domain([0, 100])
+        .range([dimensions.mainHeight - 30, 0]);
+      this.drawScaleLabel({ diagram, dimensions });
+      this.drawScale({ diagram, dimensions, yScale });
+      this.drawBars({ diagram, yScale, dimensions });
+      this.drawTooltip(diagram);
     },
-    drawBars() {
+    drawBars({ diagram, yScale, dimensions }) {
       if (this.fwLNWLData) {
+        const widthPerItem = Math.min(
+          (dimensions.width - this.scalePaddingLeft - this.scalePaddingRight) /
+            this.fwLNWLData.length,
+          180
+        );
+        const spaceBetween = widthPerItem * 0.2;
+        const afdWidth = widthPerItem * 0.5;
+        const ldcWidth = widthPerItem * 0.3;
         this.fwLNWLData.forEach((data, i) => {
-          this.drawLNWL(data, i);
-          this.drawAFD(data, i);
-          this.drawLabel(data.date, i);
+          this.drawLNWL(
+            data,
+            i,
+            diagram,
+            spaceBetween,
+            widthPerItem,
+            ldcWidth,
+            yScale
+          );
+          this.drawAFD(
+            data,
+            i,
+            diagram,
+            spaceBetween,
+            widthPerItem,
+            ldcWidth,
+            yScale,
+            afdWidth
+          );
+          this.drawLabel(data.date, i, diagram, widthPerItem, dimensions);
         });
       }
     },
-    drawLabel(date, i) {
-      this.diagram
+    drawLabel(date, i, diagram, widthPerItem, dimensions) {
+      diagram
         .append("text")
         .text(date)
         .attr("text-anchor", "middle")
@@ -412,19 +435,28 @@
         .attr(
           "transform",
           `translate(${this.scalePaddingLeft +
-            this.widthPerItem * i +
-            this.widthPerItem / 2} ${this.dimensions.mainHeight - 15})`
+            widthPerItem * i +
+            widthPerItem / 2} ${dimensions.mainHeight - 15})`
         );
     },
-    drawAFD(data, i) {
-      let afd = this.diagram
+    drawAFD(
+      data,
+      i,
+      diagram,
+      spaceBetween,
+      widthPerItem,
+      ldcWidth,
+      yScale,
+      afdWidth
+    ) {
+      let afd = diagram
         .append("g")
         .attr(
           "transform",
           `translate(${this.scalePaddingLeft +
-            this.spaceBetween / 2 +
-            this.widthPerItem * i +
-            this.ldcWidth})`
+            spaceBetween / 2 +
+            widthPerItem * i +
+            ldcWidth})`
         );
       afd
         .selectAll("rect")
@@ -452,32 +484,32 @@
           //dy gives offset of svg on page
         })
         .attr("height", d => {
-          return this.yScale(0) - this.yScale(d);
+          return yScale(0) - yScale(d);
         })
         .attr("y", (d, i) => {
           if (i === 0) {
-            return this.yScale(d);
+            return yScale(d);
           }
           if (i === 1) {
-            return this.yScale(data.above + d);
+            return yScale(data.above + d);
           }
           if (i === 2) {
-            return this.yScale(data.above + data.between + d);
+            return yScale(data.above + data.between + d);
           }
         })
-        .attr("width", this.afdWidth)
+        .attr("width", afdWidth)
         .attr("fill", (d, i) => {
           return this.$options.AFDCOLORS[i];
         });
     },
-    drawLNWL(data, i) {
-      let lnwl = this.diagram
+    drawLNWL(data, i, diagram, spaceBetween, widthPerItem, ldcWidth, yScale) {
+      let lnwl = diagram
         .append("g")
         .attr(
           "transform",
           `translate(${this.scalePaddingLeft +
-            this.spaceBetween / 2 +
-            this.widthPerItem * i})`
+            spaceBetween / 2 +
+            widthPerItem * i})`
         );
       lnwl
         .append("rect")
@@ -503,19 +535,19 @@
           //dy gives offset of svg on page
         })
         .attr("height", d => {
-          return this.yScale(0) - this.yScale(d);
+          return yScale(0) - yScale(d);
         })
         .attr("y", d => {
-          return this.yScale(d);
+          return yScale(d);
         })
-        .attr("width", this.ldcWidth)
+        .attr("width", ldcWidth)
         .attr("fill", () => {
           return this.$options.LWNLCOLORS.LDC;
         });
     },
-    drawScaleLabel() {
-      const center = this.dimensions.mainHeight / 2;
-      this.diagram
+    drawScaleLabel({ diagram, dimensions }) {
+      const center = dimensions.mainHeight / 2;
+      diagram
         .append("text")
         .text(this.$options.LEGEND)
         .attr("text-anchor", "middle")
@@ -525,27 +557,27 @@
         // translate a few mm to the right to allow for slightly higher letters
         .attr("transform", `translate(2, ${center}), rotate(-90)`);
     },
-    drawScale() {
+    drawScale({ diagram, dimensions, yScale }) {
       const yAxisLeft = d3
         .axisLeft()
         .tickSizeInner(
-          this.dimensions.width - this.scalePaddingLeft - this.scalePaddingRight
+          dimensions.width - this.scalePaddingLeft - this.scalePaddingRight
         )
         .tickSizeOuter(0)
-        .scale(this.yScale);
+        .scale(yScale);
       const yAxisRight = d3
         .axisRight()
         .tickSizeInner(
-          this.dimensions.width - this.scalePaddingLeft - this.scalePaddingRight
+          dimensions.width - this.scalePaddingLeft - this.scalePaddingRight
         )
         .tickSizeOuter(0)
-        .scale(this.yScale);
+        .scale(yScale);
 
-      this.diagram
+      diagram
         .append("g")
         .attr(
           "transform",
-          `translate(${this.dimensions.width - this.scalePaddingRight})`
+          `translate(${dimensions.width - this.scalePaddingRight})`
         )
         .call(yAxisLeft)
         .selectAll(".tick text")
@@ -564,7 +596,7 @@
         .selectAll(".tick line")
         .attr("stroke-dasharray", "none")
         .attr("stroke", "#333");
-      this.diagram
+      diagram
         .append("g")
         .attr("transform", `translate(${this.scalePaddingLeft})`)
         .call(yAxisRight)
@@ -576,7 +608,7 @@
         })
         .selectAll(".tick line")
         .attr("stroke", "transparent");
-      this.diagram.selectAll(".domain").attr("stroke", "black");
+      diagram.selectAll(".domain").attr("stroke", "black");
     }
   },
   watch: {