PageSourceSearch

https://www.dor.com.pt/js/worldmap/worldmap.js

js dor.com.pt collected 2026-10-04 15:09:55 UTC 15,011 bytes, 511 lines download raw bytes

1(function initWorldMap() {
2  // Check if DOM is already loaded, otherwise wait for it
3  if (document.readyState === "loading") {
4    document.addEventListener("DOMContentLoaded", init);
5  } else {
6    init();
7  }
8
9  function init() {
10    // Definieren der benötigten Variablen
11    const filterTriggers = document.querySelectorAll(".legend_item");
12    const pins = document.querySelectorAll(".map-pin");
13    const sites = document.querySelectorAll(".site");
14    const defaultFilter = document.querySelector(".default");
15    const svgBox = d3.select("#svg");
16    const image = svgBox.selectChild("#image");
17    const worldmap = document.querySelector(".worldmap");
18    const zoomIcon = document.getElementById("zoomIcon");
19    const zoomTooltip = zoomIcon.querySelector(".zoom-tooltip");
20    let active = {};
21    let tooltipTimeout;
22    let initialZoomApplied = false;
23    const ww = window.innerWidth;
24
25    const productionSitesLegend = document.querySelector(
26      '.legend_item[data-target="production-pins"]',
27    );
28    const productionPins = document.querySelector(".production-pins");
29
30    active.fill = defaultFilter;
31    active.pins = false;
32    active.pin = false;
33    active.infobox = false;
34    active.highlight = false;
35
36    // Initialisieren der Pin-Listener
37    initializePinListeners();
38
39    // Initialisieren der Filter-Listener
40    initializeFilterListeners();
41
42    applyActiveClassForResolution();
43
44    // Select the legend items
45    const legendItemProduction = document.querySelector(
46      ".legend_item--production",
47    );
48    const legendItemRnd = document.querySelector(".legend_item--rnd");
49
50    // Add click event listeners with toggle functionality
51    legendItemProduction.addEventListener("click", () => {
52      removeActiveClass(".rnd-sites");
53      addActiveClass(".production-sites");
54    });
55
56    legendItemRnd.addEventListener("click", () => {
57      removeActiveClass(".production-sites");
58      addActiveClass(".rnd-sites");
59    });
60
61    function addActiveClass(selector) {
62      const element = document.querySelector(selector);
63      if (element) {
64        element.classList.add("active");
65      }
66    }
67
68    function removeActiveClass(selector) {
69      const element = document.querySelector(selector);
70      if (element) {
71        element.classList.remove("active");
72      }
73    }
74
75    function applyActiveClassForResolution() {
76      const windowWidth = window.innerWidth;
77      const productionSitesElement =
78        document.querySelector(".production-sites");
79
80      if (productionSitesElement) {
81        if (windowWidth <= 768) {
82          productionSitesElement.classList.add("active");
83        } else {
84          productionSitesElement.classList.remove("active");
85        }
86      } else {
87        console.error(".production-sites element not found");
88      }
89    }
90
91    // Event-Listener für Kartenpins
92    function initializePinListeners() {
93      if (pins.length) {
94        pins.forEach((pin) => {
95          pin.addEventListener("click", handlePinClick);
96        });
97      }
98    }
99
100    // Verarbeiten von Pin-Klicks
101    function handlePinClick(e) {
102      const pin = e.currentTarget;
103      const infoBox = document.querySelector(
104        'div[data-pin="' + pin.dataset.target + '"]',
105      );
106      togglePinState(pin, infoBox);
107    }
108
109    // Ändern des Status eines Pins
110    function togglePinState(pin, infoBox) {
111      if (active.pin && active.pin !== pin) {
112        active.pin.classList.remove("map-pin--active");
113      }
114
115      if (active.infobox && active.infobox !== infoBox) {
116        active.infobox.classList.remove("site--active");
117      }
118
119      pin.classList.toggle("map-pin--active");
120      infoBox.classList.toggle("site--active");
121
122      active.infobox = active.infobox === infoBox ? false : infoBox;
123      active.pin = active.infobox ? pin : false;
124    }
125
126    // Event-Listener für Filter
127    function initializeFilterListeners() {
128      if (filterTriggers.length) {
129        filterTriggers.forEach((filterTrigger) => {
130          filterTrigger.addEventListener("click", handleFilterClick);
131        });
132      }
133    }
134
135    // Verarbeiten der Filteraktionen
136    function handleFilterClick() {
137      const action = this.dataset.action;
138
139      if (this.classList.contains("legend_item--production")) {
140        addActiveClass(".production-sites");
141      } else if (this.classList.contains("legend_item--rnd")) {
142        addActiveClass(".rnd-sites");
143      }
144
145      switch (action) {
146        case "fill":
147          handleFillAction(this);
148          break;
149        case "pin":
150          handlePinAction(this);
151          break;
152        case "highlight":
153          handleHighlightAction(this);
154          break;
155        case "clear":
156          handleClearAction();
157          break;
158      }
159    }
160
161    // Füllaktion verarbeiten
162    function handleFillAction(filterTrigger) {
163      if (active.highlight) {
164        resetHighlight();
165      }
166
167      if (active.pins) {
168        resetPins();
169      }
170
171      if (filterTrigger !== active.fill) {
172        updateActiveFill(filterTrigger);
173      } else if (filterTrigger !== defaultFilter) {
174        resetToDefaultFill();
175      }
176    }
177
178    // Aktives Fill-Element aktualisieren
179    function updateActiveFill(newFill) {
180      active.fill.classList.remove("legend_item--active");
181      const elementToUnfill = document.getElementById(
182        active.fill.dataset.target,
183      );
184      newFill.classList.add("legend_item--active");
185      const elementToFill = document.getElementById(newFill.dataset.target);
186      active.fill = newFill;
187
188      elementToFill.classList.add("fill--active");
189      elementToUnfill.classList.remove("fill--active");
190    }
191
192    // Zurücksetzen auf das Standard-Fill
193    function resetToDefaultFill() {
194      defaultFilter.classList.add("legend_item--active");
195      const elementToFill = document.getElementById(
196        defaultFilter.dataset.target,
197      );
198      const elementToUnfill = document.getElementById(
199        active.fill.dataset.target,
200      );
201      active.fill = defaultFilter;
202
203      elementToFill.classList.add("fill--active");
204      elementToUnfill.classList.remove("fill--active");
205    }
206
207    // Pin-Aktion verarbeiten
208    function handlePinAction(filterTrigger) {
209      let pinsToDisplay, pinsToRemove;
210
211      if (active.fill !== defaultFilter) {
212        resetFill();
213      }
214
215      if (active.highlight) {
216        resetHighlight();
217      }
218
219      if (active.pin) {
220        active.pin.classList.remove("map-pin--active");
221        if (active.infobox) {
222          active.infobox.classList.remove("site--active");
223        }
224      }
225
226      toggleLegendItem(filterTrigger);
227
228      if (filterTrigger === active.pins) {
229        pinsToRemove = document.querySelector(
230          "." + filterTrigger.dataset.target,
231        );
232        active.pins = false;
233      } else {
234        if (active.pins) {
235          active.pins.classList.remove("legend_item--active");
236          pinsToRemove = document.querySelector(
237            "." + active.pins.dataset.target,
238          );
239        }
240        pinsToDisplay = document.querySelector(
241          "." + filterTrigger.dataset.target,
242        );
243        active.pins = filterTrigger;
244      }
245
246      if (pinsToDisplay) {
247        displayPins(pinsToDisplay);
248      }
249
250      if (pinsToRemove) {
251        removePins(pinsToRemove);
252      }
253    }
254
255    // Umschalten der Legenden-Elemente
256    function toggleLegendItem(filterTrigger) {
257      filterTrigger.classList.toggle("legend_item--active");
258    }
259
260    // Highlight-Aktion verarbeiten
261    function handleHighlightAction(filterTrigger) {
262      if (active.fill !== defaultFilter) {
263        resetFill();
264      }
265
266      if (active.pins) {
267        resetPins();
268      }
269
270      const highlight = document.getElementById(
271        filterTrigger.dataset.continent,
272      );
273      highlight.classList.toggle("continent--active");
274      filterTrigger.classList.toggle("legend_item--active");
275
276      if (active.highlight && filterTrigger !== active.highlight) {
277        active.highlight.classList.remove("legend_item--active");
278        document
279          .getElementById(active.highlight.dataset.continent)
280          .classList.remove("continent--active");
281      }
282
283      active.highlight =
284        filterTrigger !== active.highlight ? filterTrigger : false;
285    }
286
287    // Verarbeiten der Clear-Aktion
288    function handleClearAction() {
289      if (active.fill !== defaultFilter) {
290        resetFill();
291      }
292
293      if (active.highlight) {
294        resetHighlight();
295      }
296
297      if (active.pins) {
298        resetPins();
299      }
300    }
301
302    // Zurücksetzen des Fills
303    function resetFill() {
304      active.fill.classList.remove("legend_item--active");
305      defaultFilter.classList.add("legend_item--active");
306      active.fill = defaultFilter;
307    }
308
309    // Zurücksetzen der Pins
310    function resetPins() {
311      if (active.pins) {
312        active.pins.classList.remove("legend_item--active");
313        const pinsToRemove = document.querySelector(
314          "." + active.pins.dataset.target,
315        );
316        if (pinsToRemove) {
317          removePins(pinsToRemove);
318        }
319      }
320
321      if (active.pin) {
322        active.pin.classList.remove("map-pin--active");
323
324        if (active.infobox) {
325          active.infobox.classList.remove("site--active");
326        }
327      }
328
329      active.pins = false;
330      active.pin = false;
331      active.infobox = false;
332    }
333
334    // Zurücksetzen des Highlights
335    function resetHighlight() {
336      if (active.highlight) {
337        active.highlight.classList.remove("legend_item--active");
338        document
339          .getElementById(active.highlight.dataset.continent)
340          .classList.remove("continent--active");
341        active.highlight = false;
342      }
343    }
344
345    // Pins anzeigen
346    function displayPins(element) {
347      element.classList.remove("pins--inactive");
348    }
349
350    // Pins ausblenden
351    function removePins(element) {
352      element.classList.add("pins--inactive");
353    }
354
355    // Aktualisieren der Pin-Positionen
356    function updatePinPosition() {
357      const worldmapRect = worldmap.getBoundingClientRect();
358      pins.forEach((pin) => {
359        const pinData = pin.getAttribute("data-target");
360        const correspondingBox = Array.from(sites).find(
361          (box) => box.getAttribute("data-pin") === pinData,
362        );
363
364        if (correspondingBox) {
365          positionInfoBox(correspondingBox, pin, worldmapRect);
366        }
367      });
368    }
369
370    // Positionieren der Infobox relativ zum Pin
371    function positionInfoBox(correspondingBox, pin, worldmapRect) {
372      const correspondingPin = pin.getBoundingClientRect();
373      const pinLeft = correspondingPin.left - worldmapRect.left;
374      const pinTop = correspondingPin.top - worldmapRect.top;
375
376      const offsetX = 0;
377      const offsetY = correspondingPin.height + 10;
378
379      correspondingBox.style.left = pinLeft + offsetX + "px";
380      correspondingBox.style.top = pinTop - offsetY + "px";
381    }
382
383    updatePinPosition();
384
385    // Zoom-Logik und Pinch-to-Zoom
386    if (ww > 768) {
387      function zoomed(event) {
388        const { transform } = event;
389        applyZoomTransform(transform);
390        updatePinPosition();
391        resizePins(transform.k);
392      }
393
394      function applyZoomTransform(transform) {
395        image.attr("transform", transform.toString());
396      }
397
398      function resizePins(scaleFactor) {
399        const windowWidth = window.innerWidth;
400        const pinSize = windowWidth <= 768 ? 25 : 16;
401
402        d3.selectAll(".map-pin").attr("r", pinSize / scaleFactor);
403        d3.selectAll(".map-pin").style("stroke-width", 2 / scaleFactor + "px");
404      }
405
406      // Anpassung der Pin-Größe basierend auf Zoom-Faktor
407
408      const { width, height } = image.node().getBBox();
409      const { width: svgBoxWidth, height: svgBoxHeight }
409 = svgBox
410        .node()
411        .getBoundingClientRect();
412      const minScale = Math.max(svgBoxWidth / width, svgBoxHeight / height);
413
414      const zoom = d3
415        .zoom()
416        .scaleExtent([minScale, 8])
417        .extent([
418          [0, 0],
419          [svgBoxWidth, svgBoxHeight],
420        ])
421        .translateExtent([
422          [0, 0],
423          [width, height],
424        ])
425        .on("zoom", zoomed);
426
427      svgBox.call(zoom);
428
429      const windowWidth = window.innerWidth;
430      const initialScale = windowWidth <= 768 ? 2 : 1.2;
431      svgBox
432        .transition()
433        .duration(750)
434        .call(zoom.scaleTo, initialScale)
435        .on("end", function () {
436          // Select Germany pin only after zoom transition completes
437          selectGermanyPinInitially();
438        });
439
440      // Initialisieren der Pin-Größe
441      initializePinSize();
442
443      function initializePinSize() {
444        const initialZoom = minScale;
445        resizePins(initialZoom);
446      }
447    } else {
448      // For mobile (ww <= 768), select Germany pin immediately
449      selectGermanyPinInitially();
450    }
451
452    showProductionSitesInitially();
453
454    // Produktionsstandorte anzeigen
455    function showProductionSitesInitially() {
456      if (productionSitesLegend && productionPins) {
457        productionSitesLegend.classList.add("legend_item--active");
458        productionPins.classList.remove("pins--inactive");
459        active.pins = productionSitesLegend;
460      }
461    }
462
463    // Deutschland-Pin initial auswählen
464    function selectGermanyPinInitially() {
465      const germanyPin = document.querySelector(
466        '.map-pin[data-target="info-box-production-germany"]',
467      );
468
469      if (germanyPin) {
470        germanyPin.dispatchEvent(new Event("click"));
471      } else {
472        console.error("Germany pin not found");
473      }
474    }
475
476    // Tooltip-Verhalten für das Zoom-Icon
477    worldmap.addEventListener("mouseenter", handleMapHover);
478    worldmap.addEventListener("mouseleave", handleMapMouseLeave);
479
480    zoomIcon.addEventListener("mouseenter", function () {
481      showTooltip();
482    });
483
484    zoomIcon.addEventListener("mouseleave", function () {
485      hideTooltip();
486    });
487
488    function handleMapHover() {
489      zoomIcon.classList.add("hover-zoom");
490      showTooltip();
491
492      clearTimeout(tooltipTimeout);
493      tooltipTimeout = setTimeout(function () {
494        hideTooltip();
495      }, 5000);
496    }
497
498    function handleMapMouseLeave() {
499      zoomIcon.classList.remove("hover-zoom");
500    }
501
502    function showTooltip() {
503      zoomTooltip.style.display = "block";
504      zoomTooltip.classList.remove("fade-out");
505    }
506
507    function hideTooltip() {
508      zoomTooltip.classList.add("fade-out");
509    }
510  } // end of init function
511})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.