传单地图截图
Take a screenshot of leaflet map
所以我有一张传单地图,我在上面画了一些图层(矩形)。
我想捕获该特定图层的屏幕截图,而不是整个可见地图。
我已经尝试过传单插件,但它们并没有像我期望的那样工作,而且我已经设法捕获了屏幕截图,但是使用 html2canvas 捕获了地图的整个可见部分。
我怎么能 select (捕获)只有我想在屏幕截图中的那个矩形?
或者在使用 leaflet-area-select 时可能捕获 selected 区域?
我正在使用 React 和 TypeScript。
这可以借助 leaflet-simple-map-screenshoter 和一些仔细的图像处理来完成。
Working codesandbox
这是我所做的演练:
自定义窗格
首先,让我们创建一些 custom panes 来区分镜头中我们想要的和不需要的。实际上,您所需要的只是屏幕截图中您不需要的图层,但我们会创建两个以备不时之需:
//Create a map and assign it to the map div
var map = L.map("leafletMapid", mapOptions);
// Create some custom panes
map.createPane("snapshot-pane");
map.createPane("dont-include");
现在我们可以在这些窗格中创建我们的层,无论它们是图块层还是 geojson 或路径或其他什么。让我们在“快照窗格”的镜头中包含我们想要的 baselayer 和一个 geojson,在“不包含”窗格的镜头中包含我们不想要的路径:
// Add baselayer and geojson to snapshot pane
const baselayer = L.tileLayer(url,
{ pane: "snapshot-pane" }
).addTo(map);
const greekborder = L.geoJSON(greekBorderGeoJson, {
pane: "snapshot-pane"
}).addTo(map);
// Add another polygon to the 'dont-include' pane
const serbianborder = L.polyline(serbianBorder, {
color: "darkred",
pane: "dont-include"
}).addTo(map);
设置屏幕截图:
使用截图插件,让我们设置一个截图程序。截屏器将排除 我们在“不包含”面板中设置的图层:
const snapshotOptions = {
hideElementsWithSelectors: [
".leaflet-control-container",
".leaflet-dont-include-pane",
"#snapshot-button"
],
hidden: true
};
// Add screenshotter to map
const screenshotter = new SimpleMapScreenshoter(snapshotOptions);
screenshotter.addTo(map);
自定义截图功能
我们不想使用默认的屏幕截图行为,因此我们将指定一个函数,以便在我们点击自定义按钮时触发
// define screenshot function
const takeScreenShot = () => {
// defined below
}
// Add takescreenshot function to button
const button = document.getElementById("snapshot-button");
button.addEventListener("click", takeScreenShot);
如果你查看截图插件的文档,你可以在截图后的 .then
中捕获截图者创建的图像数据:
const takeScreenShot = () => {
screenshotter
.takeScreen("image")
.then((image) => {
// Create <img> element to render img data
var img = new Image();
})
}
我们已经获取了图像数据,创建了一个新的 Image
元素,我们准备将图像数据分配给 new Image
元素。但在我们这样做之前,我们要定义一个 img.onload
函数,它将在图像数据分配给 Image
元素时触发。这个onload
必须先定义,然后我们才能分配图像源数据。
图像加载时会发生什么
加载图像时,我们想做一些事情
- 找出相关地图特征的边界
- 将这些边界转换为屏幕上的像素坐标
- 将仅包含在canvas
范围内的图像数据写入
- 将 canvas 另存为 png 文件
这是执行此操作的代码:
img.onload = () => {
// Create canvas to process image data
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// Set canvas size to the size of your resultant image
canvas.width = imageSize.x;
canvas.height = imageSize.y;
// Draw just the portion of the whole map image that contains
// your feature to the canvas
ctx.drawImage(
img,
topLeft.x,
topLeft.y,
imageSize.x,
imageSize.y,
0,
0,
imageSize.x,
imageSize.y
);
// Create URL for resultant png
var imageurl = canvas.toDataURL("image/png");
const resultantImage = new Image();
resultantImage.style = "border: 1px solid black";
resultantImage.src = imageurl;
// Append new image to body for nice visual in this example answer
document.body.appendChild(canvas);
canvas.toBlob(function (blob) {
// saveAs function installed as part of leaflet snapshot package
saveAs(blob, "greek_border.png");
});
};
花点时间看一下,如果您有任何问题,请告诉我。
一个Image.onload
函数在图像src
赋值时触发,所以我们先定义函数,然后赋值src
:
const takeScreenShot = () => {
screenshotter
.takeScreen("image")
.then((image) => {
// Create <img> element to render img data
var img = new Image();
img.onload = () => {
// all that code in the prev code block
}
// set the image source to what the snapshotter captured
// img.onload will fire AFTER this
img.src = image;
})
}
就是这样。您将下载一个图像,其中包含地图的所有层,控件除外,以及您在“不包含”窗格中排除的任何内容。图像将被裁剪到您的特征的边界。
请注意,如果部分地图项位于可见地图边界之外,这将不起作用。虽然可以使用地图边界之外的部分功能实现您想要的效果,但要做到这一点 复杂得多 ,尤其是如果您希望在背景中使用 baselayer。
另外,你说你最初使用的是 React。如果您在反应项目中使用传单,我强烈建议您使用反应传单。在您指定不使用它之前,我最初将此答案写为 react-leaflet 答案,但这里是 react-leaflet 版本:
React-leaflet codesandbox
所以我有一张传单地图,我在上面画了一些图层(矩形)。 我想捕获该特定图层的屏幕截图,而不是整个可见地图。 我已经尝试过传单插件,但它们并没有像我期望的那样工作,而且我已经设法捕获了屏幕截图,但是使用 html2canvas 捕获了地图的整个可见部分。 我怎么能 select (捕获)只有我想在屏幕截图中的那个矩形?
或者在使用 leaflet-area-select 时可能捕获 selected 区域?
我正在使用 React 和 TypeScript。
这可以借助 leaflet-simple-map-screenshoter 和一些仔细的图像处理来完成。
Working codesandbox
这是我所做的演练:
自定义窗格
首先,让我们创建一些 custom panes 来区分镜头中我们想要的和不需要的。实际上,您所需要的只是屏幕截图中您不需要的图层,但我们会创建两个以备不时之需:
//Create a map and assign it to the map div
var map = L.map("leafletMapid", mapOptions);
// Create some custom panes
map.createPane("snapshot-pane");
map.createPane("dont-include");
现在我们可以在这些窗格中创建我们的层,无论它们是图块层还是 geojson 或路径或其他什么。让我们在“快照窗格”的镜头中包含我们想要的 baselayer 和一个 geojson,在“不包含”窗格的镜头中包含我们不想要的路径:
// Add baselayer and geojson to snapshot pane
const baselayer = L.tileLayer(url,
{ pane: "snapshot-pane" }
).addTo(map);
const greekborder = L.geoJSON(greekBorderGeoJson, {
pane: "snapshot-pane"
}).addTo(map);
// Add another polygon to the 'dont-include' pane
const serbianborder = L.polyline(serbianBorder, {
color: "darkred",
pane: "dont-include"
}).addTo(map);
设置屏幕截图:
使用截图插件,让我们设置一个截图程序。截屏器将排除 我们在“不包含”面板中设置的图层:
const snapshotOptions = {
hideElementsWithSelectors: [
".leaflet-control-container",
".leaflet-dont-include-pane",
"#snapshot-button"
],
hidden: true
};
// Add screenshotter to map
const screenshotter = new SimpleMapScreenshoter(snapshotOptions);
screenshotter.addTo(map);
自定义截图功能
我们不想使用默认的屏幕截图行为,因此我们将指定一个函数,以便在我们点击自定义按钮时触发
// define screenshot function
const takeScreenShot = () => {
// defined below
}
// Add takescreenshot function to button
const button = document.getElementById("snapshot-button");
button.addEventListener("click", takeScreenShot);
如果你查看截图插件的文档,你可以在截图后的 .then
中捕获截图者创建的图像数据:
const takeScreenShot = () => {
screenshotter
.takeScreen("image")
.then((image) => {
// Create <img> element to render img data
var img = new Image();
})
}
我们已经获取了图像数据,创建了一个新的 Image
元素,我们准备将图像数据分配给 new Image
元素。但在我们这样做之前,我们要定义一个 img.onload
函数,它将在图像数据分配给 Image
元素时触发。这个onload
必须先定义,然后我们才能分配图像源数据。
图像加载时会发生什么
加载图像时,我们想做一些事情
- 找出相关地图特征的边界
- 将这些边界转换为屏幕上的像素坐标
- 将仅包含在canvas 范围内的图像数据写入
- 将 canvas 另存为 png 文件
这是执行此操作的代码:
img.onload = () => {
// Create canvas to process image data
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// Set canvas size to the size of your resultant image
canvas.width = imageSize.x;
canvas.height = imageSize.y;
// Draw just the portion of the whole map image that contains
// your feature to the canvas
ctx.drawImage(
img,
topLeft.x,
topLeft.y,
imageSize.x,
imageSize.y,
0,
0,
imageSize.x,
imageSize.y
);
// Create URL for resultant png
var imageurl = canvas.toDataURL("image/png");
const resultantImage = new Image();
resultantImage.style = "border: 1px solid black";
resultantImage.src = imageurl;
// Append new image to body for nice visual in this example answer
document.body.appendChild(canvas);
canvas.toBlob(function (blob) {
// saveAs function installed as part of leaflet snapshot package
saveAs(blob, "greek_border.png");
});
};
花点时间看一下,如果您有任何问题,请告诉我。
一个Image.onload
函数在图像src
赋值时触发,所以我们先定义函数,然后赋值src
:
const takeScreenShot = () => {
screenshotter
.takeScreen("image")
.then((image) => {
// Create <img> element to render img data
var img = new Image();
img.onload = () => {
// all that code in the prev code block
}
// set the image source to what the snapshotter captured
// img.onload will fire AFTER this
img.src = image;
})
}
就是这样。您将下载一个图像,其中包含地图的所有层,控件除外,以及您在“不包含”窗格中排除的任何内容。图像将被裁剪到您的特征的边界。
请注意,如果部分地图项位于可见地图边界之外,这将不起作用。虽然可以使用地图边界之外的部分功能实现您想要的效果,但要做到这一点 复杂得多 ,尤其是如果您希望在背景中使用 baselayer。
另外,你说你最初使用的是 React。如果您在反应项目中使用传单,我强烈建议您使用反应传单。在您指定不使用它之前,我最初将此答案写为 react-leaflet 答案,但这里是 react-leaflet 版本: