comparison client/src/components/fairway/AvailableFairwayDepth.vue @ 3267:b07b4cca5e34

client: diagram-template: implement pdf-template for fairway availability diagram * implement default template * add some template elements * fit d3-styles to get renderd on pdf
author Fadi Abbud <fadi.abbud@intevation.de>
date Wed, 15 May 2019 13:18:33 +0200
parents a7d44d1ae57d
children 1a97a079ef1b
comparison
equal deleted inserted replaced
3266:3dee5cf16a58 3267:b07b4cca5e34
12 :key="index" 12 :key="index"
13 > 13 >
14 {{ entry }} 14 {{ entry }}
15 </li> 15 </li>
16 </ul> 16 </ul>
17 <div class="my-auto mx-auto">
18 <select
19 v-model="form.template"
20 class="form-control d-block custom-select-sm w-100 mt-1"
21 >
22 <option
23 v-for="template in templates"
24 :value="template"
25 :key="template.name"
26 >
27 {{ template.name }}
28 </option>
29 </select>
30 <button
31 @click="downloadPDF"
32 type="button"
33 class="btn btn-sm btn-info d-block w-100 mt-1"
34 >
35 <translate>Export to PDF</translate>
36 </button>
37 </div>
17 </div> 38 </div>
18 <div :id="containerId" class="mx-auto my-auto diagram-container"></div> 39 <div
40 ref="diagramContainer"
41 :id="containerId"
42 class="mx-auto my-auto diagram-container"
43 ></div>
19 </div> 44 </div>
20 </div> 45 </div>
21 </template> 46 </template>
22 47
23 <style></style> 48 <style></style>
41 import app from "@/main"; 66 import app from "@/main";
42 import debounce from "debounce"; 67 import debounce from "debounce";
43 import { diagram } from "@/lib/mixins"; 68 import { diagram } from "@/lib/mixins";
44 import { mapState } from "vuex"; 69 import { mapState } from "vuex";
45 import filters from "@/lib/filters.js"; 70 import filters from "@/lib/filters.js";
71 import jsPDF from "jspdf";
72 import canvg from "canvg";
73 import { pdfgen } from "@/lib/mixins";
46 74
47 const hoursInDays = x => x / 24; 75 const hoursInDays = x => x / 24;
48 76
49 export default { 77 export default {
50 mixins: [diagram], 78 mixins: [diagram, pdfgen],
51 data() { 79 data() {
52 return { 80 return {
53 containerId: "availablefairwaydepth", 81 containerId: "availablefairwaydepth",
54 loading: false, 82 loading: false,
55 width: 1000, 83 width: 1000,
60 scalePaddingLeft: 50, 88 scalePaddingLeft: 50,
61 paddingTop: 10, 89 paddingTop: 10,
62 diagram: null, 90 diagram: null,
63 yScale: null, 91 yScale: null,
64 barsWidth: 60, 92 barsWidth: 60,
65 dimensions: null 93 dimensions: null,
94 pdf: {
95 doc: null,
96 width: null,
97 height: null
98 },
99 form: {
100 template: null
101 },
102 templateData: null,
103 templates: [],
104 defaultemplate: {
105 name: "Default",
106 properties: {
107 paperSize: "a4"
108 },
109 elements: [
110 {
111 type: "diagram",
112 position: "topleft",
113 offset: { x: 20, y: 60 },
114 width: 290,
115 height: 100
116 },
117 {
118 type: "diagramtitle",
119 position: "topleft",
120 offset: { x: 20, y: 20 },
121 fontsize: 20,
122 color: "steelblue"
123 },
124 {
125 type: "diagramlegend",
126 position: "topleft",
127 offset: { x: 30, y: 160 },
128 color: "black"
129 }
130 ]
131 }
66 }; 132 };
67 }, 133 },
68 created() { 134 created() {
69 window.addEventListener("resize", debounce(this.drawDiagram), 100); 135 window.addEventListener("resize", debounce(this.drawDiagram), 100);
70 }, 136 },
71 mounted() { 137 mounted() {
72 this.drawDiagram(); 138 this.drawDiagram();
139 this.templates[0] = this.defaultemplate;
140 this.form.template = this.templates[0];
141 this.templateData = this.templates[0];
73 }, 142 },
74 computed: { 143 computed: {
75 ...mapState("fairwayavailability", [ 144 ...mapState("fairwayavailability", [
76 "selectedFairwayAvailabilityFeature", 145 "selectedFairwayAvailabilityFeature",
77 "fwData", 146 "fwData",
92 title() { 161 title() {
93 return `Available Fairway Depth: ${ 162 return `Available Fairway Depth: ${
94 this.featureName 163 this.featureName
95 } (${filters.surveyDate(this.fromDate)} - ${filters.surveyDate( 164 } (${filters.surveyDate(this.fromDate)} - ${filters.surveyDate(
96 this.toDate 165 this.toDate
97 )}) ${this.$gettext(this.frequency)}`; 166 )}) ${this.$gettext(this.fre40quency)}`;
98 }, 167 },
99 featureName() { 168 featureName() {
100 return this.selectedFairwayAvailabilityFeature.properties.name; 169 return this.selectedFairwayAvailabilityFeature.properties.name;
101 } 170 }
102 }, 171 },
103 methods: { 172 methods: {
173 downloadPDF() {
174 this.pdf.doc = new jsPDF(
175 "l",
176 "mm",
177 this.templateData.properties.paperSize
178 );
179 // pdf width and height in millimeter (landscape)
180 this.pdf.width =
181 this.templateData.properties.paperSize === "a3" ? 420 : 297;
182 this.pdf.height =
183 this.templateData.properties.paperSize === "a3" ? 297 : 210;
184 if (this.templateData) {
185 let defaultOffset = { x: 0, y: 0 },
186 defaultFontSize = 10,
187 defaultColor = "black";
188 this.templateData.elements.forEach(e => {
189 switch (e.type) {
190 case "diagram": {
191 this.addDiagram(
192 e.position,
193 e.offset || defaultOffset,
194 e.width,
195 e.height
196 );
197 break;
198 }
199 case "diagramtitle": {
200 this.addDiagramTitle(
201 e.position,
202 e.offset || defaultOffset,
203 e.fontsize || defaultFontSize,
204 e.color || defaultColor
205 );
206 break;
207 }
208 case "diagramlegend": {
209 this.addDiagramLegend(
210 e.position,
211 e.offset || defaultOffset,
212 e.color || defaultColor
213 );
214 }
215 }
216 });
217 }
218 this.pdf.doc.save(`Available Fairway Depth: ${this.featureName}`);
219 },
220 addDiagram(position, offset, width, height) {
221 let x = offset.x,
222 y = offset.y;
223 var svg = this.$refs.diagramContainer.innerHTML;
224 if (svg) {
225 svg = svg.replace(/\r?\n|\r/g, "").trim();
226 }
227 if (!width) {
228 width = this.templateData.properties.paperSize === "a3" ? 380 : 290;
229 }
230 if (!height) {
231 height = this.templateData.properties.paperSize === "a3" ? 130 : 100;
232 }
233 if (["topright", "bottomright"].indexOf(position) !== -1) {
234 x = this.pdf.width - offset.x - width;
235 }
236 if (["bottomright", "bottomleft"].indexOf(position) !== -1) {
237 y = this.pdf.height - offset.y - height;
238 }
239 var canvas = document.createElement("canvas");
240 canvas.width = window.innerWidth;
241 canvas.height = window.innerHeight / 2;
242 canvg(canvas, svg, {
243 ignoreMouse: true,
244 ignoreAnimation: true,
245 ignoreDimensions: true
246 });
247 var imgData = canvas.toDataURL("image/png");
248 this.pdf.doc.addImage(imgData, "PNG", x, y, width, height);
249 },
250 addDiagramTitle(position, offset, size, color) {
251 let x = offset.x,
252 y = offset.y;
253 let title = this.title;
254 let width =
255 (this.pdf.doc.getStringUnitWidth(title) * size) / (72 / 25.6) +
256 size / 2;
257 // if position is on the right, x needs to be calculate with pdf width and
258 // the size of the element
259 if (["topright", "bottomright"].indexOf(position) !== -1) {
260 x = this.pdf.width - offset.x - width;
261 }
262 if (["bottomright", "bottomleft"].indexOf(position) !== -1) {
263 y = this.pdf.height - offset.y - this.getTextHeight(1);
264 }
265 this.pdf.doc.setTextColor(color);
266 this.pdf.doc.setFontSize(size);
267 this.pdf.doc.setFontStyle("bold");
268 this.pdf.doc.text(title, x, y, { baseline: "hanging" });
269 },
270 addDiagramLegend(position, offset, color) {
271 let x = offset.x,
272 y = offset.y;
273
274 this.pdf.doc.setFontSize(10);
275 this.pdf.doc.setTextColor(color);
276 this.pdf.doc.setDrawColor("rgb(255, 133, 94)");
277 this.pdf.doc.setFillColor("rgb(255, 133, 94)");
278 this.pdf.doc.rect(x, y, 8, 4, "FD");
279 this.pdf.doc.text(">= LDC [h]", x + 10, y + 3);
280
281 this.pdf.doc.setDrawColor("rgb(255, 66, 79)");
282 this.pdf.doc.setFillColor("rgb(255, 66, 79)");
283 this.pdf.doc.rect(x, y + 5, 8, 4, "FD");
284 this.pdf.doc.text("< 200.00 [h]", x + 10, y + 8);
285
286 this.pdf.doc.setDrawColor("rgb(255, 115, 124)");
287 this.pdf.doc.setFillColor("rgb(255, 115, 124)");
288 this.pdf.doc.rect(x, y + 10, 8, 4, "FD");
289 this.pdf.doc.text(">= 200.00 [h]", x + 10, y + 13);
290
291 this.pdf.doc.setDrawColor("rgb(255, 153, 160)");
292 this.pdf.doc.setFillColor("rgb(255, 153, 160)");
293 this.pdf.doc.rect(x, y + 15, 8, 4, "FD");
294 this.pdf.doc.text(">= 230.00 [h]", x + 10, y + 18);
295
296 this.pdf.doc.setDrawColor("rgb(45, 132, 179)");
297 this.pdf.doc.setFillColor("rgb(45, 132, 179)");
298 this.pdf.doc.rect(x, y + 20, 8, 4, "FD");
299 this.pdf.doc.text(">= 250.00 [h]", x + 10, y + 23);
300 },
104 legendStyle(index) { 301 legendStyle(index) {
105 if (index == 0) return `background-color: ${this.$options.COLORS.LDC};`; 302 if (index == 0) return `background-color: ${this.$options.COLORS.LDC};`;
106 if (index < 4) 303 if (index < 4)
107 return `background-color: ${this.$options.COLORS.REST[index - 1]};`; 304 return `background-color: ${this.$options.COLORS.REST[index - 1]};`;
108 return `background-color: ${this.$options.COLORS.HIGHEST};`; 305 return `background-color: ${this.$options.COLORS.HIGHEST};`;
211 drawScale() { 408 drawScale() {
212 const yAxis = d3.axisLeft().scale(this.yScale); 409 const yAxis = d3.axisLeft().scale(this.yScale);
213 this.diagram 410 this.diagram
214 .append("g") 411 .append("g")
215 .attr("transform", `translate(${this.scalePaddingLeft})`) 412 .attr("transform", `translate(${this.scalePaddingLeft})`)
216 .call(yAxis); 413 .call(yAxis)
414 .selectAll(".tick text")
415 .attr("fill", "black")
416 .select(function() {
417 return this.parentNode;
418 })
419 .selectAll(".tick line")
420 .attr("stroke", "black");
421 this.diagram.selectAll(".domain").attr("stroke", "black");
217 } 422 }
218 }, 423 },
219 LEGEND: app.$gettext("Sum of days"), 424 LEGEND: app.$gettext("Sum of days"),
220 COLORS: { 425 COLORS: {
221 LDC: "#FF855E", 426 LDC: "#FF855E",