duh*_*ime 9 javascript svg matrix linear-algebra leaflet
简短版本:如何将SVG路径添加到Leaflet地图,以便在地图坐标更改时路径将更新(例如,在缩放更改或幻灯片上)?
长版:你好,我有一个包含建筑轮廓的地形图.在对图像进行地理校正后,我使用Photoshop将栅格数据转换为SVG.我知道描述SVG边界的边界框的地理坐标,并知道SVG路径元素的内部坐标.我想知道现在将SVG的路径元素中描述的建筑物添加到Leaflet地图的最佳方法.
这是一个小提琴,显示红色SVG图像的边界框和蓝色的建筑物:http://jsfiddle.net/duhaime/4vL925Lj/正如您所看到的,建筑物相对于边界框尚未正确定向.
我最初计划对齐建筑物是使用一次性脚本将路径元素从SVG坐标系转换为lat,long坐标,然后使用我用于绘制边界框的折线函数在地图上绘制建筑物:
var polyline = L.polyline(
[upperLeft, upperRight, lowerRight, lowerLeft, upperLeft],
{color: 'red', className: 'bounding-box', weight: 2}
).addTo(map);
Run Code Online (Sandbox Code Playgroud)
这种方法的问题在于Leaflet折线无法绘制Bezier曲线,这些曲线存在于上面的SVG路径元素中.作为一种解决方法,我认为我可以对贝塞尔曲线使用线性近似,尽管这可能会成为一个相当大的工作量.
最后我意识到上面小提琴中的边界框的SVG使用贝塞尔曲线,这让我想到我可能会使用矩阵变换将构建SVG的坐标空间转换到Leaflet坐标空间.上面的小提琴使用样本矩阵变换css规则来变换建筑物层.
在深入了解这个兔子洞之前,我想问一下:其他人认为最好的方法是将上述SVG中的建筑物的路径添加到小提琴中的Leaflet地图中?我将非常感谢其他人可以就此问题提供的任何建议!
进展:我决定简化这个问题并弄清楚如何使用矩阵变换将一个div("A")转换为另一个div("B")的纵横比.在这样做的过程中,我制作了一个小的Python脚本,它将输入div的像素坐标和所需的输出div B的像素坐标作为输入.该脚本生成变换矩阵X,使得AX = B. 该脚本在内部记录,并伴随着小提琴.
我还提出了一个要点,即推导出变换矩阵,将SVG空间中的点投射到适当的lat,lng coords中.最糟糕的情况是,我可以对SVG路径元素进行分区,使用变换矩阵获取每个点的点积,并使用传单绘制折线以绘制建筑物.那将失去Bezier曲线......
以下示例使用折线值来演示该方法,因为它将在缩放/平移 Leaflet 地图期间应用于 svg 路径和其他形状。基本上创建了一个 SVG 图层,并将所有 svg 元素添加到其中。
<head>
<title>Untitled</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js" ></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css" />
<style type="text/css">
<!--
#map {
width: 500px;
height: 500px;
}
-->
</style>
</head>
<body>
<div id="map"></div>
</body>
<script>
// create the map object itself
centerCoordinates = new L.LatLng(41.307, -72.928);
var map = new L.Map("map", {
center: centerCoordinates,
zoom: 14,
zoomControl: false
});
// position the zoom controls in the bottom right hand corner
L.control.zoom({
position: 'bottomright',
zoom: 14,
maxZoom: 20,
minZoom: 12,
}).addTo(map);
map.addLayer(new L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> © <a href="http://cartodb.com/attributions">CartoDB</a>',
subdomains: 'abcd',
maxZoom: 19
}));
// specify the coordinates of the overlay's bounding box
var upperLeft = L.latLng(41.329785, -72.927220);
var lowerLeft = L.latLng(41.304414, -72.945686);
var upperRight = L.latLng(41.319186, -72.903268);
var lowerRight = L.latLng(41.293816, -72.921718);
/*
// create a red polyline from an array of LatLng points
var polyline = L.polyline(
[upperLeft, upperRight, lowerRight, lowerLeft, upperLeft], {
color: 'red',
className: 'bounding-box',
weight: 2
}
).addTo(map);
*/
//---CREATE SVG---
map._initPathRoot() //---creates an svg layer---
var MySVG=document.querySelector("svg") //---access svg element---
var NS="http://www.w3.org/2000/svg"
//---place svg elems in here---
var SvgElemG=document.createElementNS(NS,"g")
MySVG.appendChild(SvgElemG)
//---zooming the map's SVG elements---
map.on("viewreset", adjustSVGElements);
//---add svg polygon---
var polygon=document.createElementNS(NS,"polyline")
polygon.setAttribute("stroke-width",1)
polygon.setAttribute("fill","none")
polygon.setAttribute("stroke","red")
//---convert latLng to x,y---
var xyUL=map.latLngToLayerPoint(upperLeft)
var xyLL=map.latLngToLayerPoint(lowerLeft)
var xyLR=map.latLngToLayerPoint(lowerRight)
var xyUR=map.latLngToLayerPoint(upperRight)
var points=[xyUL.x,xyUL.y,xyLL.x,xyLL.y,xyLR.x,xyLR.y,xyUR.x,xyUR.y,xyUL.x,xyUL.y].toString()
polygon.setAttribute('points',points)
//--required for zoom---
var svgPnt=L.point(0,0) //--reference for translate--
var latLng=map.layerPointToLatLng(svgPnt)
var lat=latLng.lat
var lng=latLng.lng
polygon.setAttribute("lat",lat)
polygon.setAttribute("lng",lng)
//---retain the zoom level at its creation--
polygon.setAttribute('initZoom',map.getZoom())
SvgElemG.appendChild(polygon)
//--- on map zoom - fired via map event: viewreset---
function adjustSVGElements()
{
var mapZoom=map.getZoom()
var svgElems=SvgElemG.childNodes
for(var k=0;k<svgElems.length;k++)
{
var svgElem=svgElems.item(k)
var lat=parseFloat(svgElem.getAttribute("lat"))
var lng=parseFloat(svgElem.getAttribute("lng"))
var latLng= new L.latLng(lat, lng)
var transX=map.latLngToLayerPoint(latLng).x
var transY=map.latLngToLayerPoint(latLng).y
//---trash previous transform---
svgElem.setAttribute("transform","") //---required for IE
svgElem.removeAttribute("transform")
var transformRequestObj=MySVG.createSVGTransform()
var animTransformList=svgElem.transform
//---get baseVal to access/place object transforms
var transformList=animTransformList.baseVal
//---translate----
transformRequestObj.setTranslate( transX, transY)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
//---scale---
var initZoom=parseFloat(svgElem.getAttribute("initZoom"))
var scale = (Math.pow(2, mapZoom)/2)/(Math.pow(2, initZoom)/2);
transformRequestObj.setScale(scale,scale)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
}
}
</script>Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2253 次 |
| 最近记录: |