How to export vuelayers map to png or jpeg? - vue.js

How would I adapt #ghettovoice JSFiddle that saves a map to PDF to save the map to a JPEG or PNG? I have no idea how to attempt this problem so ideally if you know hoe to do it you can explain the logic behind it.
exportMap: function () {
var map = this.$refs.map
map.once('rendercomplete', function () {
var mapCanvas = document.createElement('canvas');
var size = map.getSize();
mapCanvas.width = size[0];
mapCanvas.height = size[1];
var mapContext = mapCanvas.getContext('2d');
Array.prototype.forEach.call(
document.querySelectorAll('.ol-layer canvas'),
function (canvas) {
if (canvas.width > 0) {
var opacity = canvas.parentNode.style.opacity;
mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
var transform = canvas.style.transform;
// Get the transform parameters from the style's transform matrix
var matrix = transform
.match(/^matrix\(([^(]*)\)$/)[1]
.split(',')
.map(Number);
// Apply the transform to the export map context
CanvasRenderingContext2D.prototype.setTransform.apply(
mapContext,
matrix
);
mapContext.drawImage(canvas, 0, 0);
}
}
);
if (navigator.msSaveBlob) {
// link download attribuute does not work on MS browsers
navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png');
} else {
var link = document.getElementById('image-download');
link.href = mapCanvas.toDataURL();
link.click();
}
});
map.renderSync();
}

The problem was a combination of missing dependencies (namely FileSaver.js and fakerator.js) and a cross origin server block (CORS block) (Browsers automatically prevent httpRequests to a different domain name unless the server allows it). The first one is fixed by installing the packages while the second one is resolved by setting the crossOrigin Attribute of the ImageWMSLayer to null in my case but possibly to 'Anonymous' for other sources. Hope this helped someone else :)

Related

Semantic Tokens in MarkupString / MarkupContent

Is it possible to use MarkdownString/MarkupContent with code or pre with span to emulate semantic tokens in Hover? If so, is it possible to access the colors from the user's theme using only the CSS on the span elements? Ideally I would like to avoid using anything VSCode specific.
I saw https://github.com/microsoft/vscode/issues/97409 but there was no solution.
If you want to manually set colors for code you can try this:
// using your fileSelector
let disposable = vscode.languages.registerHoverProvider('plaintext', {
provideHover(document, position) {
const codeBlock = `<code><span style="color:#f00;background-color:#fff;">const</span> a = 12</code>`;
const markdown = new vscode.MarkdownString();
// markdown.appendCodeblock(codeBlock, "javascript");
markdown.appendMarkdown(codeBlock);
markdown.supportHtml = true;
markdown.isTrusted = true;
return new vscode.Hover(markdown, new vscode.Range(position, position));
}
});
<pre> also works, instead of <code>, but I think <code> looks better.

Panning disabled when remove leaflet map from dom -vuejs

I have a leaflet map in my vuejs app. I need to refresh my map when users update their search terms.
I notice that my code is not replacing the map. Instead, my code adds more divs to the existing map. This is problematic because it interferes with user panning and also overloads the page with unwanted data.
I have tried deleting the existing map in several ways...
My current approach is this...
var container = L.DomUtil.get("leafletMapId");
if (container != null) {
while (container.firstChild)
container.removeChild(containerfirstChild);
}
container._leaflet_id = null;
} else {
console.log("container was null");
}
var myMap = L.map("leafletMapId", {
layers: [streetTilesLayer],
scrollWheelZoom: true
}).setView(this.center, this.zoom);
This appears to effectively empty the map div. However, it leads to an error when I click and attempt to pan the map:
leaflet-src.js?e11e:2558 Uncaught TypeError: Cannot read property
'offsetWidth' of null
at getSizedParentNode (leaflet-src.js?e11e:2558)
at NewClass._onDown (leaflet-src.js?e11e:5902)
at HTMLDivElement.handler (leaflet-src.js?e11e:2679)
I have also tried this...
var container = L.DomUtil.get("leafletMapId");
if (container != null) {
container.innerHTML = "";
container._leaflet_id = null;
} else {
console.log("container was null");
}
var myMap = L.map("leafletMapId", {
layers: [streetTilesLayer],
scrollWheelZoom: true
}).setView(this.center, this.zoom);
This causes the same error.
This seems to completely replace the leaflet map with no errors...
$("#leafletMapId").remove();
var g = document.createElement("div");
g.setAttribute("id", "leafletMapId");
document.getElementById("main-div").appendChild(g);
var myMap = L.map("leafletMapId", {
layers: [streetTilesLayer],
scrollWheelZoom: true
}).setView(this.center, this.zoom);
where this the div with ID "leafletMapId" is a child of the div with ID "main-div".
I've been struggling with this problem for a day and the answer given by GNG was the only one that solved it for me. I had to combine his answer with another one I found, so I could reload my map with a different set of markers each time and still have panning controls. My final code is this.
$("#map").remove();
var g = document.createElement("div");
g.setAttribute("id", "map");
document.getElementById("main-div").appendChild(g);
document.getElementById('map').innerHTML = `<div id="map" class="map map-home" style="height: 300px; margin-top: 50px"></div>`;
var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
osmAttribution = 'Attribution',
osmLayer = new L.TileLayer(osmUrl, {maxZoom: 18, attribution: osmAttribution});
var map = L.map('map').setView([latitud, longitud], 15).addLayer(osmLayer);
L.marker([latitud, longitud])
.addTo(map)
.bindPopup("mensaje")
.openPopup();
I post this not as an answer to the original question, but to further comment on the answer given by GNG.

Adding embedded mode in docusaurus

I am using docusaurus 1.14.4
I need to create embedded mode for each document which remove header, footer and left navigation.
Page url look like this http://localhost:3000/...../?mode=emb
I figure out a way by adding this piece of script to each md file
<script>
function getParameterByName(name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
var mode = getParameterByName('mode');
if (mode === 'emb') {
setTimeout(()=>{
let list = ['fixedHeaderContainer', 'docsNavContainer', 'nav-footer', 'docs-prevnext'];
for (var itemClassName of list) {
var item = document.getElementsByClassName(itemClassName)[0]
item.parentNode.removeChild(item)
}
document.getElementsByClassName('navPusher')[0].style.paddingTop = 0;
document.getElementsByClassName('mainContainer')[0].style.paddingTop = 0;
}, 0)
}
</script>
It work but does not look like a proper way. Can anyone suggest a better way?
Docusaurus maintainer here. There's no supported way of doing this. May I know what your motivations for doing this are?

Panning the map to certain extent javascript API

I want to limit map extent to the initial extent of the map and limit user from panning more than certain extent.
I tried following but nothing has changed:
map = new Map( "map" , {
basemap: "gray",
center: [-85.416, 49.000],
zoom : 6,
logo: false,
sliderStyle: "small"
});
dojo.connect(map, "onExtentChange", function (){
var initExtent = map.extent;
var extent = map.extent.getCenter();
if(initExtent.contains(extent)){}
else{map.setExtent(initExtent)}
});
Just to flesh out Simon's answer somewhat, and give an example. Ideally you need two variables at the same scope as map:
initExtent to store the boundary of your valid extent, and
validExtent to store the last valid extent found while panning, so that you can bounce back to it.
I've used the newer dojo.on event syntax as well for this example, it's probably a good idea to move to this as per the documentation's recommendation - I assume ESRI will discontinue the older style at some point.
var map;
var validExtent;
var initExtent;
[...]
require(['dojo/on'], function(on) {
on(map, 'pan', function(evt) {
if ( !initExtent.contains(evt.extent) ) {
console.log('Outside bounds!');
} else {
console.log('Updated extent');
validExtent = evt.extent;
}
});
on(map, 'pan-end', function(evt) {
if ( !initExtent.contains(evt.extent) ) {
map.setExtent(validExtent);
}
});
});
You can do the same with the zoom events, or use extent-change if you want to trap everything. Up to you.
It looks like your extent changed function is setting the initial extent variable to the maps current extent and then checking if that extent contains the current extents centre point - which of course it always will.
Instead, declare initExtent at the same scope of the map variable. Then, change the on load event to set this global scope variable rather than a local variable. In the extent changed function, don't update the value of initExtent, simply check the initExtent contains the entire of the current extent.
Alternatively you could compare each bound of the current extent to each bound of the initExtent, e.g. is initExtent.xmin < map.extent.xmin and if any are, create a new extent setting any exceeded bounds to the initExtent values.
The only problem is these techniques will allow the initExtent to be exceeded briefly, but will then snap the extent back once the extent changed function fires and catches up.
I originally posted this solution on gis.stackexchange in answer to this question: https://gis.stackexchange.com/a/199366
Here's a code sample from that post:
//This function limits the extent of the map to prevent users from scrolling
//far away from the initial extent.
function limitMapExtent(map) {
var initialExtent = map.extent;
map.on('extent-change', function(event) {
//If the map has moved to the point where it's center is
//outside the initial boundaries, then move it back to the
//edge where it moved out
var currentCenter = map.extent.getCenter();
if (!initialExtent.contains(currentCenter) &&
event.delta.x !== 0 && event.delta.y !== 0) {
var newCenter = map.extent.getCenter();
//check each side of the initial extent and if the
//current center is outside that extent,
//set the new center to be on the edge that it went out on
if (currentCenter.x < initialExtent.xmin) {
newCenter.x = initialExtent.xmin;
}
if (currentCenter.x > initialExtent.xmax) {
newCenter.x = initialExtent.xmax;
}
if (currentCenter.y < initialExtent.ymin) {
newCenter.y = initialExtent.ymin;
}
if (currentCenter.y > initialExtent.ymax) {
newCenter.y = initialExtent.ymax;
}
map.centerAt(newCenter);
}
});
}
And here's a working jsFiddle example: http://jsfiddle.net/sirhcybe/aL1p24xy/

open layer GetFeatureInfo proxy setting

I have problems with this line,
OpenLayers.ProxyHost = "proxy.cgi?url=";
What should do other than writing above line in open layer code set?
My information
I try to get feature information of WMS image using WMSGetFeatureInfo command.I am using openlayer 2.10 ,geoserver and apache-tomcat-6.0.35.I can run tomcat using localhost:8080 and geoserver using localhost:8080/geoserver.
I am new to open layer and i see Frequently Asked Questions about the OpenLayers project but still can't figure out the answer.Yours any answers are very help full for me?
Thanks for your valuable time.
This link could be useful: Openlayers Proxy path usage
Some of the tasks that OpenLayers performs (including WFS requests) require the use of a proxy script because of restrictions in JavaScript on the use of XMLHTTPRequest making requests to remote servers.
Add that specific declaration before setting the map.
Start from here:
http://openlayers.org/dev/examples/2
Example of code:
/*
* Fix for OpenLayers using 900913 for web mercator and AGS using 102113 (it must run before map init)
OpenLayers.Layer.WMS.prototype.getFullRequestString = function(newParams,altUrl) {
try {
var projectionCode=typeof this.options.projection == 'undefined' ? this.map.getProjection() : this.options.projection;
} catch(err){
var projectionCode=this.map.getProjection();
}
this.params.SRS = projectionCode=="none" ? null : projectionCode;
return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);
}
*/
OpenLayers.ProxyHost = proxyPath;
var options = {
projection: mercator, //EPSG:3785/900913
displayProjection: geographic, //EPSG:4326
theme: null,
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
maxResolution: 156543.0339,
units: 'm',
controls: [],
numZoomLevels: MAX_ZOOM_LEVEL,
allOverlays: true
};
OpenLayers.Util.DEFAULT_PRECISION = 18;
mp = new OpenLayers.Map('map', options);
addMaps();
addControls();
mp.addLayers([googlePhysical, googleSatellite, googleStreets, googleHybrid]);
//Enabling the preferred layers with a delay of 450 to be able to load the external backgrounds
setTimeout(setInitialLayersDiv, 450);
if (!mp.getCenter()) {
if (document.getElementById('userMapExtent').value != '') {
var sExtent = document.getElementById('userMapExtent').value.split(',');
mp.zoomToExtent(new OpenLayers.Bounds(sExtent[0], sExtent[1], sExtent[2], sExtent[3]), true);
} else {
mp.zoomToExtent(europeGoogleExtent);
}
}
J('#google_loading').hide('slow');