From 924212396045f03322651fd42d7fb03db73bcce1 Mon Sep 17 00:00:00 2001
From: Olivier Maury <olivier.maury@inrae.fr>
Date: Thu, 9 Nov 2023 18:09:17 +0100
Subject: [PATCH] =?UTF-8?q?Int=C3=A9grer=20les=20cr=C3=A9dits=20dans=20la?=
 =?UTF-8?q?=20carte.=20fixes=20#11?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../www/client/ui/map/CanvasAttributions.java | 126 ++++++++++++++++++
 .../www/client/ui/map/CanvasWidget.java       |  78 +++++++++++
 2 files changed, 204 insertions(+)
 create mode 100644 www-client/src/main/java/fr/agrometinfo/www/client/ui/map/CanvasAttributions.java
 create mode 100644 www-client/src/main/java/fr/agrometinfo/www/client/ui/map/CanvasWidget.java

diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/ui/map/CanvasAttributions.java b/www-client/src/main/java/fr/agrometinfo/www/client/ui/map/CanvasAttributions.java
new file mode 100644
index 0000000..ed0c221
--- /dev/null
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/ui/map/CanvasAttributions.java
@@ -0,0 +1,126 @@
+package fr.agrometinfo.www.client.ui.map;
+
+import java.util.StringJoiner;
+
+import com.google.gwt.canvas.dom.client.Context2d;
+import com.google.gwt.canvas.dom.client.Context2d.TextAlign;
+import com.google.gwt.canvas.dom.client.TextMetrics;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.CanvasElement;
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
+
+import elemental2.dom.DomGlobal;
+import ol.Collection;
+import ol.Map;
+import ol.layer.Base;
+import ol.layer.Group;
+
+/**
+ * Draw the attributions box into HTML canvas of OpenLayers to allow map export.
+ *
+ * At bottom right.
+ *
+ * @author Olivier Maury
+ */
+public final class CanvasAttributions extends CanvasWidget {
+
+    /**
+     * Line height for the lines of title.
+     */
+    private static final int LINE_HEIGHT = 8;
+
+    /**
+     * Margin around the box.
+     */
+    private static final int MARGIN = 2;
+
+    /**
+     * Padding around the text.
+     */
+    private static final int PADDING = 5;
+
+    private static String getAttributions(final Base layer) {
+        GWT.log("CanvasAttributions.getAttributions()");
+        final Object value = layer.get(TileSuppliers.ATTRIBUTIONS);
+        if (value == null) {
+            return null;
+        }
+        String attributions;
+        if (value instanceof String[]) {
+            attributions = String.join("", (String[]) value);
+        } else if (value instanceof String) {
+            attributions = (String) value;
+        } else {
+            return null;
+        }
+        attributions = attributions.trim();
+        if (attributions.startsWith("-")) {
+            attributions = attributions.substring(1).trim();
+        }
+        if (attributions.isEmpty()) {
+            return null;
+        }
+        return attributions;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param map OpenLayers map.
+     */
+    public CanvasAttributions(final Map map) {
+        super(map);
+    }
+
+    /**
+     * Draw the attribution box with background.
+     */
+    @Override
+    protected void draw() {
+        GWT.log("CanvasAttributions.draw()");
+        final CanvasElement canvas = getCanvas();
+        if (canvas == null) {
+            DomGlobal.console.error("Canvas must not be null!");
+            return;
+        }
+        final StringJoiner sj = new StringJoiner(" - ");
+        final Collection<Base> layers = getMap().getLayerGroup().getLayers();
+        for (final Base l : layers.getArray()) {
+            String attributions = getAttributions(l);
+            if (attributions != null) {
+                sj.add(attributions);
+            } else if (l instanceof Group) {
+                final Group group = (Group) l;
+                for (final Base layer : group.getLayers().getArray()) {
+                    if (layer.getVisible()) {
+                        attributions = getAttributions(layer);
+                        if (attributions != null) {
+                            sj.add(attributions);
+                        }
+                    }
+                }
+            } else {
+                GWT.log("CanvasAttributions.draw() " + l.getClass().getCanonicalName());
+            }
+        }
+        final DivElement div = Document.get().createDivElement();
+        div.setInnerHTML(sj.toString());
+        final String line = div.getInnerText().trim();
+        final Context2d ctx = canvas.getContext2d();
+        ctx.setFont("8px \"Helvetica Neue\", Helvetica, Arial, sans-serif");
+        final TextMetrics measure = ctx.measureText(line);
+        final double width = measure.getWidth();
+        ctx.setFillStyle("rgba(255, 255, 255, .8)");
+        ctx.fillRect(//
+                canvas.getWidth() - width - MARGIN - 2 * PADDING, //
+                canvas.getHeight() - LINE_HEIGHT - MARGIN - 2 * PADDING, //
+                width + 2 * PADDING, //
+                LINE_HEIGHT + 2 * PADDING);
+        ctx.setFillStyle("#000000");
+        ctx.setTextAlign(TextAlign.LEFT);
+        ctx.fillText(line, //
+                canvas.getWidth() - width - MARGIN - PADDING, //
+                canvas.getHeight() - MARGIN - PADDING);
+    }
+}
diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/ui/map/CanvasWidget.java b/www-client/src/main/java/fr/agrometinfo/www/client/ui/map/CanvasWidget.java
new file mode 100644
index 0000000..f8715a5
--- /dev/null
+++ b/www-client/src/main/java/fr/agrometinfo/www/client/ui/map/CanvasWidget.java
@@ -0,0 +1,78 @@
+package fr.agrometinfo.www.client.ui.map;
+
+import com.google.gwt.dom.client.CanvasElement;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NodeList;
+
+import ol.Map;
+
+/**
+ * Ancestor for all widgets drawn on the OpenLayers canvas.
+ *
+ * @author Olivier Maury
+ */
+abstract class CanvasWidget {
+    /**
+     * OpenLayers map.
+     */
+    private final Map openLayersMap;
+
+    /**
+     * HTML canvas element.
+     */
+    private CanvasElement canvas;
+
+    /**
+     * Constructor.
+     *
+     * @param map OpenLayers map.
+     */
+    protected CanvasWidget(final Map map) {
+        openLayersMap = map;
+        openLayersMap.on("postcompose", e -> this.draw());
+    }
+
+    /**
+     * Draw the widget when map changes.
+     */
+    protected abstract void draw();
+
+    /**
+     * Find a canvas element in the tree.
+     *
+     * @param root root element
+     * @return found or null
+     */
+    private CanvasElement findCanvas(final Element root) {
+        final NodeList<Element> elems = root.getElementsByTagName("canvas");
+        for (int i = 0; i < elems.getLength(); i++) {
+            final Element elem = elems.getItem(i);
+            if ("canvas".equalsIgnoreCase(elem.getTagName())) {
+                return (CanvasElement) elem;
+            }
+            final CanvasElement found = findCanvas(elem);
+            if (found != null) {
+                return found;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @return HTML canvas element.
+     */
+    protected CanvasElement getCanvas() {
+        if (canvas == null) {
+            canvas = findCanvas(openLayersMap.getViewport());
+        }
+        return canvas;
+    }
+
+    /**
+     * @return OpenLayers map.
+     */
+    protected Map getMap() {
+        return openLayersMap;
+    }
+
+}
-- 
GitLab