Mercurial > gemma
comparison client/src/components/fairway/AvailableFairwayDepthLNWL.vue @ 3992:2f024d6189ca
Reverted merge with diagram-cleanup -- its not yet ready.
author | Sascha Wilde <wilde@intevation.de> |
---|---|
date | Wed, 17 Jul 2019 15:12:23 +0200 |
parents | 2aaa1948b525 |
children | 44060b9027da |
comparison
equal
deleted
inserted
replaced
3991:06096a7ce1c5 | 3992:2f024d6189ca |
---|---|
1 <template> | 1 <template> |
2 <div class="d-flex flex-column flex-fill"> | 2 <div class="d-flex flex-column flex-fill"> |
3 <UIBoxHeader icon="chart-area" :title="title" :closeCallback="close" /> | 3 <UIBoxHeader icon="chart-area" :title="title" :closeCallback="close" /> |
4 <UISpinnerOverlay v-if="loading" /> | |
4 <div class="d-flex flex-fill"> | 5 <div class="d-flex flex-fill"> |
5 <DiagramLegend> | 6 <DiagramLegend> |
6 <div v-for="(entry, index) in legendLNWL" :key="index" class="legend"> | 7 <div v-for="(entry, index) in legendLNWL" :key="index" class="legend"> |
7 <span | 8 <span |
8 :style=" | 9 :style=" |
41 >Download CSV</a | 42 >Download CSV</a |
42 > | 43 > |
43 </div> | 44 </div> |
44 </DiagramLegend> | 45 </DiagramLegend> |
45 <div | 46 <div |
46 class="d-flex flex-fill justify-content-center align-items-center" | 47 ref="diagramContainer" |
47 :id="containerId" | 48 :id="containerId" |
48 > | 49 class="diagram-container flex-fill" |
49 <div v-if="!fwLNWLData.length"> | 50 ></div> |
50 <translate>No data available.</translate> | |
51 </div> | |
52 </div> | |
53 </div> | 51 </div> |
54 </div> | 52 </div> |
55 </template> | 53 </template> |
54 | |
55 <style></style> | |
56 | 56 |
57 <script> | 57 <script> |
58 /* This is Free Software under GNU Affero General Public License v >= 3.0 | 58 /* This is Free Software under GNU Affero General Public License v >= 3.0 |
59 * without warranty, see README.md and license for details. | 59 * without warranty, see README.md and license for details. |
60 * | 60 * |
69 * * Thomas Junk <thomas.junk@intevation.de> | 69 * * Thomas Junk <thomas.junk@intevation.de> |
70 * * Markus Kottländer <markus.kottlaender@intevation.de> | 70 * * Markus Kottländer <markus.kottlaender@intevation.de> |
71 * * Fadi Abbud <fadi.abbud@intevation.de> | 71 * * Fadi Abbud <fadi.abbud@intevation.de> |
72 */ | 72 */ |
73 import * as d3 from "d3"; | 73 import * as d3 from "d3"; |
74 import app from "@/main"; | |
75 import debounce from "debounce"; | |
74 import { mapState } from "vuex"; | 76 import { mapState } from "vuex"; |
77 import filters from "@/lib/filters.js"; | |
75 import { diagram, pdfgen, templateLoader } from "@/lib/mixins"; | 78 import { diagram, pdfgen, templateLoader } from "@/lib/mixins"; |
76 import filters from "@/lib/filters.js"; | 79 import { HTTP } from "@/lib/http"; |
80 import { displayError } from "@/lib/errors"; | |
81 import { defaultDiagramTemplate } from "@/lib/DefaultDiagramTemplate"; | |
77 | 82 |
78 export default { | 83 export default { |
79 mixins: [diagram, pdfgen, templateLoader], | 84 mixins: [diagram, pdfgen, templateLoader], |
85 components: { | |
86 DiagramLegend: () => import("@/components/DiagramLegend") | |
87 }, | |
80 data() { | 88 data() { |
81 return { | 89 return { |
82 containerId: "availablefairwaydepthlnwl-diagram-container", | 90 containerId: "availablefairwaydepthlnwl-diagram-container", |
91 resizeListenerFunction: null, | |
92 loading: false, | |
83 scalePaddingLeft: 60, | 93 scalePaddingLeft: 60, |
84 scalePaddingRight: 0, | 94 scalePaddingRight: 0, |
85 paddingTop: 25, | 95 paddingTop: 25, |
86 colors: { | 96 pdf: { |
87 afd: ["#3636ff", "#f49b7f", "#e15472"], | 97 doc: null, |
88 lnwl: "#97ddf3" | 98 width: null, |
99 height: null | |
100 }, | |
101 form: { | |
102 template: null | |
103 }, | |
104 templateData: null, | |
105 templates: [], | |
106 defaultTemplate: defaultDiagramTemplate | |
107 }; | |
108 }, | |
109 created() { | |
110 this.resizeListenerFunction = debounce(this.drawDiagram, 100); | |
111 window.addEventListener("resize", this.resizeListenerFunction); | |
112 }, | |
113 destroyed() { | |
114 window.removeEventListener("resize", this.resizeListenerFunction); | |
115 }, | |
116 mounted() { | |
117 // Nasty but necessary if we don't want to use the updated hook to re-draw | |
118 // the diagram because this would re-draw it also for irrelevant reasons. | |
119 // In this case we need to wait for the child component (DiagramLegend) to | |
120 // render. According to the docs (https://vuejs.org/v2/api/#mounted) this | |
121 // should be possible with $nextTick() but it doesn't work because it does | |
122 // not guarantee that the DOM is not only updated but also re-painted on the | |
123 // screen. | |
124 setTimeout(this.drawDiagram, 150); | |
125 | |
126 this.templates[0] = this.defaultTemplate; | |
127 this.form.template = this.templates[0]; | |
128 this.templateData = this.form.template; | |
129 HTTP.get("/templates/diagram", { | |
130 headers: { | |
131 "X-Gemma-Auth": localStorage.getItem("token"), | |
132 "Content-type": "text/xml; charset=UTF-8" | |
89 } | 133 } |
90 }; | 134 }) |
135 .then(response => { | |
136 if (response.data.length) { | |
137 this.templates = response.data; | |
138 this.form.template = this.templates[0]; | |
139 this.templates[this.templates.length] = this.defaultTemplate; | |
140 this.applyChange(); | |
141 } | |
142 }) | |
143 .catch(e => { | |
144 const { status, data } = e.response; | |
145 displayError({ | |
146 title: this.$gettext("Backend Error"), | |
147 message: `${status}: ${data.message || data}` | |
148 }); | |
149 }); | |
91 }, | 150 }, |
92 computed: { | 151 computed: { |
93 ...mapState("fairwayavailability", [ | 152 ...mapState("fairwayavailability", [ |
94 "selectedFairwayAvailabilityFeature", | 153 "selectedFairwayAvailabilityFeature", |
95 "fwLNWLData", | 154 "fwLNWLData", |
146 } | 205 } |
147 }, | 206 }, |
148 methods: { | 207 methods: { |
149 legendStyle(index) { | 208 legendStyle(index) { |
150 const style = { | 209 const style = { |
151 0: `background-color: ${this.colors.lnwl};`, | 210 0: `background-color: ${this.$options.LWNLCOLORS.LDC};`, |
152 1: `background-color: ${this.colors.afd[2]};`, | 211 1: `background-color: ${this.$options.AFDCOLORS[2]};`, |
153 2: `background-color: ${this.colors.afd[1]};`, | 212 2: `background-color: ${this.$options.AFDCOLORS[1]};`, |
154 3: `background-color: ${this.colors.afd[0]};` | 213 3: `background-color: ${this.$options.AFDCOLORS[0]};` |
155 }; | 214 }; |
156 return style[index]; | 215 return style[index]; |
216 }, | |
217 applyChange() { | |
218 if (this.form.template.hasOwnProperty("properties")) { | |
219 this.templateData = this.defaultTemplate; | |
220 return; | |
221 } | |
222 if (this.form.template) { | |
223 this.loadTemplates("/templates/diagram/" + this.form.template.name) | |
224 .then(response => { | |
225 this.prepareImages(response.data.template_data.elements).then( | |
226 values => { | |
227 values.forEach(v => { | |
228 response.data.template_data.elements[v.index].url = v.url; | |
229 }); | |
230 this.templateData = response.data.template_data; | |
231 } | |
232 ); | |
233 }) | |
234 .catch(e => { | |
235 const { status, data } = e.response; | |
236 displayError({ | |
237 title: this.$gettext("Backend Error"), | |
238 message: `${status}: ${data.message || data}` | |
239 }); | |
240 }); | |
241 } | |
242 }, | |
243 downloadPDF() { | |
244 let title = `Available Fairway Depth vs LNWL: ${this.featureName}`; | |
245 this.generatePDF({ | |
246 templateData: this.templateData, | |
247 diagramTitle: title | |
248 }); | |
249 this.pdf.doc.save(`Available Fairway Depth LNWL: ${this.featureName}`); | |
157 }, | 250 }, |
158 addDiagramLegend(position, offset, color) { | 251 addDiagramLegend(position, offset, color) { |
159 let x = offset.x, | 252 let x = offset.x, |
160 y = offset.y; | 253 y = offset.y; |
161 this.pdf.doc.setFontSize(10); | 254 this.pdf.doc.setFontSize(10); |
168 } | 261 } |
169 if (["bottomright", "bottomleft"].indexOf(position) !== -1) { | 262 if (["bottomright", "bottomleft"].indexOf(position) !== -1) { |
170 y = this.pdf.height - offset.y - this.getTextHeight(6); | 263 y = this.pdf.height - offset.y - this.getTextHeight(6); |
171 } | 264 } |
172 this.pdf.doc.setTextColor(color); | 265 this.pdf.doc.setTextColor(color); |
173 this.pdf.doc.setDrawColor(this.colors.lnwl); | 266 this.pdf.doc.setDrawColor(this.$options.LWNLCOLORS.LDC); |
174 this.pdf.doc.setFillColor(this.colors.lnwl); | 267 this.pdf.doc.setFillColor(this.$options.LWNLCOLORS.LDC); |
175 this.pdf.doc.roundedRect(x, y, 10, 4, 1.5, 1.5, "FD"); | 268 this.pdf.doc.roundedRect(x, y, 10, 4, 1.5, 1.5, "FD"); |
176 this.pdf.doc.text(this.legendLNWL[0], x + 12, y + 3); | 269 this.pdf.doc.text(this.legendLNWL[0], x + 12, y + 3); |
177 | 270 |
178 this.pdf.doc.setDrawColor(this.colors.afd[2]); | 271 this.pdf.doc.setDrawColor(this.$options.AFDCOLORS[2]); |
179 this.pdf.doc.setFillColor(this.colors.afd[2]); | 272 this.pdf.doc.setFillColor(this.$options.AFDCOLORS[2]); |
180 this.pdf.doc.roundedRect(x, y + 5, 10, 4, 1.5, 1.5, "FD"); | 273 this.pdf.doc.roundedRect(x, y + 5, 10, 4, 1.5, 1.5, "FD"); |
181 this.pdf.doc.text(this.legendLNWL[1], x + 12, y + 8); | 274 this.pdf.doc.text(this.legendLNWL[1], x + 12, y + 8); |
182 | 275 |
183 this.pdf.doc.setDrawColor(this.colors.afd[1]); | 276 this.pdf.doc.setDrawColor(this.$options.AFDCOLORS[1]); |
184 this.pdf.doc.setFillColor(this.colors.afd[1]); | 277 this.pdf.doc.setFillColor(this.$options.AFDCOLORS[1]); |
185 this.pdf.doc.roundedRect(x, y + 10, 10, 4, 1.5, 1.5, "FD"); | 278 this.pdf.doc.roundedRect(x, y + 10, 10, 4, 1.5, 1.5, "FD"); |
186 this.pdf.doc.text(this.legendLNWL[2], x + 12, y + 13); | 279 this.pdf.doc.text(this.legendLNWL[2], x + 12, y + 13); |
187 | 280 |
188 this.pdf.doc.setDrawColor(this.colors.afd[0]); | 281 this.pdf.doc.setDrawColor(this.$options.AFDCOLORS[0]); |
189 this.pdf.doc.setFillColor(this.colors.afd[0]); | 282 this.pdf.doc.setFillColor(this.$options.AFDCOLORS[0]); |
190 this.pdf.doc.roundedRect(x, y + 15, 10, 4, 1.5, 1.5, "FD"); | 283 this.pdf.doc.roundedRect(x, y + 15, 10, 4, 1.5, 1.5, "FD"); |
191 this.pdf.doc.text(this.legendLNWL[3], x + 12, y + 18); | 284 this.pdf.doc.text(this.legendLNWL[3], x + 12, y + 18); |
192 }, | 285 }, |
193 close() { | 286 close() { |
194 this.$store.commit("application/paneSetup", "DEFAULT"); | 287 this.$store.commit("application/paneSetup", "DEFAULT"); |
195 }, | 288 }, |
196 getPrintLayout() { | 289 getPrintLayout(svgHeight) { |
197 return { | 290 return { |
198 main: { top: 0, right: 20, bottom: 50, left: 20 } | 291 main: { top: 0, right: 20, bottom: 50, left: 20 }, |
292 nav: { | |
293 top: svgHeight - 65, | |
294 right: 20, | |
295 bottom: 30, | |
296 left: 80 | |
297 } | |
199 }; | 298 }; |
200 }, | 299 }, |
201 drawDiagram() { | 300 drawDiagram() { |
202 const elem = document.querySelector("#" + this.containerId); | 301 const elem = document.querySelector("#" + this.containerId); |
203 const svgWidth = elem != null ? elem.clientWidth : 0; | 302 const svgWidth = elem != null ? elem.clientWidth : 0; |
204 const svgHeight = elem != null ? elem.clientHeight : 0; | 303 const svgHeight = elem != null ? elem.clientHeight : 0; |
205 const layout = this.getPrintLayout(); | 304 const layout = this.getPrintLayout(svgHeight); |
206 const dimensions = this.getDimensions({ | 305 const dimensions = this.getDimensions({ |
207 svgHeight, | 306 svgHeight, |
208 svgWidth, | 307 svgWidth, |
209 ...layout | 308 ...layout |
210 }); | 309 }); |
211 d3.select("#" + this.containerId + " svg").remove(); | 310 d3.select(".diagram-container svg").remove(); |
212 this.renderTo({ element: "#" + this.containerId, dimensions }); | 311 this.renderTo({ element: ".diagram-container", dimensions }); |
213 }, | 312 }, |
214 drawTooltip(diagram) { | 313 drawTooltip(diagram) { |
215 diagram | 314 diagram |
216 .append("text") | 315 .append("text") |
217 .text("") | 316 .text("") |
341 } | 440 } |
342 }) | 441 }) |
343 .attr("transform", `translate(0 ${this.paddingTop})`) | 442 .attr("transform", `translate(0 ${this.paddingTop})`) |
344 .attr("width", afdWidth) | 443 .attr("width", afdWidth) |
345 .attr("fill", (d, i) => { | 444 .attr("fill", (d, i) => { |
346 return this.colors.afd[i]; | 445 return this.$options.AFDCOLORS[i]; |
347 }); | 446 }); |
348 }, | 447 }, |
349 drawLNWL(data, i, diagram, spaceBetween, widthPerItem, ldcWidth, yScale) { | 448 drawLNWL(data, i, diagram, spaceBetween, widthPerItem, ldcWidth, yScale) { |
350 let lnwl = diagram | 449 let lnwl = diagram |
351 .append("g") | 450 .append("g") |
385 return yScale(d); | 484 return yScale(d); |
386 }) | 485 }) |
387 .attr("transform", `translate(0 ${this.paddingTop})`) | 486 .attr("transform", `translate(0 ${this.paddingTop})`) |
388 .attr("width", ldcWidth) | 487 .attr("width", ldcWidth) |
389 .attr("fill", () => { | 488 .attr("fill", () => { |
390 return this.colors.lnwl; | 489 return this.$options.LWNLCOLORS.LDC; |
391 }); | 490 }); |
392 }, | 491 }, |
393 drawScaleLabel({ diagram, dimensions }) { | 492 drawScaleLabel({ diagram, dimensions }) { |
394 diagram | 493 diagram |
395 .append("text") | 494 .append("text") |
396 .text(this.$gettext("Percent")) | 495 .text(this.$options.LEGEND) |
397 .attr("text-anchor", "middle") | 496 .attr("text-anchor", "middle") |
398 .attr("x", 0) | 497 .attr("x", 0) |
399 .attr("y", 0) | 498 .attr("y", 0) |
400 .attr("dy", "20") | 499 .attr("dy", "20") |
401 // translate a few mm to the right to allow for slightly higher letters | 500 // translate a few mm to the right to allow for slightly higher letters |
470 }, | 569 }, |
471 watch: { | 570 watch: { |
472 fwLNWLData() { | 571 fwLNWLData() { |
473 this.drawDiagram(); | 572 this.drawDiagram(); |
474 } | 573 } |
574 }, | |
575 LEGEND: app.$gettext("Percent"), | |
576 AFDCOLORS: ["#3636ff", "#f49b7f", "#e15472"], | |
577 LWNLCOLORS: { | |
578 LDC: "#97ddf3", | |
579 HDC: "#43FFE1" | |
475 } | 580 } |
476 }; | 581 }; |
477 </script> | 582 </script> |