# HG changeset patch # User Thomas Junk # Date 1562837364 -7200 # Node ID b7dfee369f2ffecadfc20d1faf38caad640657ef # Parent e4e496ae797467c8ac72d2603fe2ff2900284e9e available_fairwaydepthLNWL: factor out sideeffects and render offscreen diff -r e4e496ae7974 -r b7dfee369f2f client/src/components/fairway/AvailableFairwayDepthLNWL.vue --- 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: {