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 0000000000000000000000000000000000000000..ed0c22161cfa82ab66802597e756abe0749e6c41 --- /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 0000000000000000000000000000000000000000..f8715a5c38b4bb6becfe4e5184c07463edc2c09e --- /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; + } + +}