2

I can save the map to a PNG image, but how can I add the scale-line control to this canvas?

// export png
document.getElementById('export-png').addEventListener('click', function() {
  map.once('postcompose', function(event) {
    var canvasElement = event.context.canvas;
    var MIME_TYPE = "image/png";
    var imgURL = canvasElement.toDataURL(MIME_TYPE);
    var dlLink = document.createElement('a');
    dlLink.download = "carte"; //fileName;
    dlLink.href = imgURL;
    dlLink.dataset.downloadurl = [MIME_TYPE, dlLink.download, dlLink.href].join(':');
    document.body.appendChild(dlLink);
    dlLink.click();
    document.body.removeChild(dlLink);
  });
  map.renderSync();
});

2 Answers 2

1

Note that in the next release https://github.com/openlayers/openlayers/blob/master/changelog/upgrade-notes.md OpenLayers will change from having a single canvas for all layers to a canvas for each layer which won't be compatible with saving complete maps. However for 5.3 and below the ol-ext library includes canvas controls for scaleline, attribution and title https://viglino.github.io/ol-ext/examples/canvas/map.canvas.control.html In many cases the code for individual controls can be copied from the source and customised without needing the whole library https://viglino.github.io/ol-ext/dist/ol-ext.js

Sign up to request clarification or add additional context in comments.

3 Comments

Ok, I'm using actually Ol 4.4 because of incompatible dependencies with higher versions (geoportail Plugin in France).
so for the canvas divided into layers, I will notify when these dependencies evolve. Will there be a method or function to associate these individual canvas into one for export? As for the line scale , if it's not too complicated, I'll see the code
Just search the .js source for "Scale Line Control integrated in the canvas", it ends at "Title Control integrated in the canvas" and has no dependencies so works if copied and pasted. I've used it here mikenunn.16mb.com/demo/scalerings.html running on OL3 and customised to add scale rings based on the line intervals. In the next version don't think OpenLayers will have any built in method to combine canvases, but it should be possible with some add-on code.
1

Scale line control is an HTML element, so you really cannot do that as is. You need to draw a line on the map canvas itself and after each map move, update that line denoting the actual length in map units.

Assuming you are using a metric projection, a 50 pixel line at a 0.2 resolution denotes

50px x 0.2m/px = 10m

Check the link here for exporting a map to PNG:

https://openlayers.org/en/v4.6.5/examples/export-map.html

I modified the code so as to draw a 200 meter long line on the canvas and denote the scale by writing 200m over it. It is quick and dirty, but should point you in the direction.

// this example uses FileSaver.js for which we don't have an externs file.
var map = new ol.Map({
  layers: [
    new ol.layer.Tile({
      source: new ol.source.OSM()
    }),
    new ol.layer.Vector({
      source: new ol.source.Vector({
        url: 'https://openlayers.org/en/v4.6.5/examples/data/geojson/countries.geojson',
        format: new ol.format.GeoJSON()
      })
    })
  ],
  target: 'map',
  controls: ol.control.defaults({
    attributionOptions: {
      collapsible: false
    }
  }),
  view: new ol.View({
    center: ol.proj.transform([28.9, 41.1],"EPSG:4326","EPSG:3857"),
    zoom: 18
  })
});

document.getElementById('export-png').addEventListener('click', function() {
  map.once('postcompose', function(event) {
    var canvas = event.context.canvas;
    var ctx = canvas.getContext("2d");
    ctx.strokeStyle = "#0000FF";
    ctx.lineWidth = 5;
    ctx.beginPath();
    ctx.moveTo(10, map.getSize()[1]-10);
    ctx.lineTo(200/map.getView().getResolution(), map.getSize()[1]-10);
    ctx.stroke();
    ctx.font = "20px Arial";
    ctx.fillText("200m", 10, map.getSize()[1]-10);
    if (navigator.msSaveBlob) {
      navigator.msSaveBlob(canvas.msToBlob(), 'map.png');
    } else {
      canvas.toBlob(function(blob) {
        saveAs(blob, 'map.png');
      });
    }
  });
  map.renderSync();
});

3 Comments

Hi Ulas and thanks I'm interesting to a code sample please
Check the code I provided and see if it works for you. You need to elaborate it, but it should give you a go.
Thanks. actually it shows a line with FileSaver.js, but the more I zoom in and the smaller it is when it should be the opposite

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.