反转 L:CRS 的 Y 轴。Vue2-Leaflet 上的简单地图
Invert Y axis of L:CRS.Simple map on Vue2-Leaflet
我正在使用 Vue2-Leaflet 的 L.CRS.Simple 开发一个地图应用程序,我想反转我的地图的 y 轴,如反转 y 轴的 Leaflet documentation. I found a similar question , and it seems my problem is the same, so my question is: how do I integrate the same 中所述,但是使用 vue2-leaflet 包?
这是我的代码:
<template>
<body>
<div>
<li v-for="(message, index) in messageList" :item="message" :key="index">
{{ message }}
</li>
</div>
<l-map class="map" ref="map" :min-zoom="minZoom" :crs="crs">
<l-tile-layer :url="url"></l-tile-layer>
<!-- <l-image-overlay :url="url" :bounds="bounds" /> -->
<l-grid-layer class="grid" :tile-component="tileComponent"></l-grid-layer>
<l-marker v-for="star in stars" :key="star.id" :lat-lng="star">
<l-icon
:icon-size="[25, 25]"
icon-url="https://image.flaticon.com/icons/png/512/304/304378.png"
></l-icon>
<!-- <l-icon :icon-size="[32, 37]" icon-url="/images/star.png"></l-icon> -->
<l-popup class="popup">
<em class="popup-bold">Name: </em>{{ star.name }}<br>
<em class="popup-bold">Longitud: </em>{{ star.lng }}<br>
<em class="popup-bold">Latitud: </em>-{{ star.lat }}<br>
</l-popup>
</l-marker>
</l-map>
</body>
</template>
<script>
import L from "leaflet";
import { CRS } from "leaflet";
import {
LMap,
LTileLayer,
LMarker,
LImageOverlay,
LPopup,
LPolyline,
LIcon,
LGridLayer
} from "vue2-leaflet";
export default {
name: "Map",
components: {
LMap,
LTileLayer,
LMarker,
LImageOverlay,
LPopup,
LPolyline,
LIcon,
LGridLayer
},
props: {
msg: {
type: String
}
},
data() {
return {
url: "https://wallpaperboat.com/wp-content/uploads/2019/10/high-resolution-black-background-08.jpg",
bounds: [
[-2600, -2700],[1000, 3000]
],
minZoom: 0.5,
crs: L.CRS.Simple,
stars: [],
messageList: [],
tileComponent: {
name: "tile-component",
props: {
coords: {
type: Object,
required: true
}
},
template: '<div style="outline:1px solid #38c9d386; height:40rem; width:40rem;"></div>'
}
};
},
watch: {
msg: function() {
this.messageList.push(this.msg);
}
},
mounted() {
this.$refs.map.mapObject.setView([526, -68], 1);
this.$http
.get("https://pyet2m3rzl.execute-api.us-east-1.amazonaws.com/test/outscapebackend")
.then(response => {
return response.json();
})
.then(data => {
const resultArray = [];
for (let key in data) {
resultArray.push(data[key]);
}
this.stars = resultArray;
});
},
methods: {}
};
</script>
<style scoped>
...
</style>
如果我没理解错的话,你想反转所有 L.LatLng
的 Y 坐标,而不仅仅是图块坐标(这是 TMS 用例),这样Y 坐标在 向下 时增长。换句话说,如果我有类似...
L.marker([0,0]).addTo(map).bindPopup('y=0,x=0', {autoClose:false}).openPopup();
L.marker([100,50]).addTo(map).bindPopup('y=100,x=50', {autoClose:false}).openPopup();
...默认值看起来像...
...但您希望它看起来像...
(如果Y坐标在L.LatLng
的shorthand形式中排在第一位,请重新阅读Leaflet tutorial on L.CRS.Simple where the issue is explained, as well as lon lat lon lat lon)。
关于 Leaflet 内部的一些解释:Leaflet CRS 将 LatLng
坐标转换为像素坐标。例如默认L.CRS.EPSG3857
,屏幕Y坐标根据纬度的余弦得到traverse cylindrical projection.
对于 L.CRS.Simple
也存在这种翻译,因为存在古怪的差异。对于数学家来说,Y 坐标向上 因为这就是 cartesian plane 的工作原理:
但是,对于计算机程序员来说,Y 坐标会向下,因为屏幕上 that's how pixels are indexed(至少,几十年来一直是惯例):
为了解决这个问题,Leaflet 实现 affine transformations (which take into account the Leaflet quirks for zoom levels), and then L.CRS.Simple
使用这样的仿射变换来反转 Y 坐标(因此 L.CRS.Simple
就像笛卡尔平面而不是像素平面):
L.CRS.Simple = L.Util.extend({}, L.CRS, {
projection: L.Projection.LonLat,
transformation: L.Transformation(1, 0, -1, 0),
/* snip */
这相当于指定一个affine transformation matrix like
( 1 0 )
( 0 -1 )
因此,考虑到这一点,您的问题的答案变为 "you should define a new CRS with a custom affine transformation that maps 1 unit of «latitude» into 1 downwards pixel"。
此时,您应该阅读 Leaflet tutorial on extending Leaflet classes,但它的 TL;DR 版本是:
var CRSPixel = L.Util.extend(L.CRS.Simple, {
transformation: new L.Transformation(1,0,1,0)
});
然后将传递该自定义 CRS 的地图定义为地图的 crs
选项,然后一切正常。 Here's a working example with vanilla Leaflet(即无 vue)
有了这些信息,您应该能够使该技术适应您的 Vue 代码,稍微注意 import
所有需要的 Leaflet 位。
我正在使用 Vue2-Leaflet 的 L.CRS.Simple 开发一个地图应用程序,我想反转我的地图的 y 轴,如反转 y 轴的 Leaflet documentation. I found a similar question
这是我的代码:
<template>
<body>
<div>
<li v-for="(message, index) in messageList" :item="message" :key="index">
{{ message }}
</li>
</div>
<l-map class="map" ref="map" :min-zoom="minZoom" :crs="crs">
<l-tile-layer :url="url"></l-tile-layer>
<!-- <l-image-overlay :url="url" :bounds="bounds" /> -->
<l-grid-layer class="grid" :tile-component="tileComponent"></l-grid-layer>
<l-marker v-for="star in stars" :key="star.id" :lat-lng="star">
<l-icon
:icon-size="[25, 25]"
icon-url="https://image.flaticon.com/icons/png/512/304/304378.png"
></l-icon>
<!-- <l-icon :icon-size="[32, 37]" icon-url="/images/star.png"></l-icon> -->
<l-popup class="popup">
<em class="popup-bold">Name: </em>{{ star.name }}<br>
<em class="popup-bold">Longitud: </em>{{ star.lng }}<br>
<em class="popup-bold">Latitud: </em>-{{ star.lat }}<br>
</l-popup>
</l-marker>
</l-map>
</body>
</template>
<script>
import L from "leaflet";
import { CRS } from "leaflet";
import {
LMap,
LTileLayer,
LMarker,
LImageOverlay,
LPopup,
LPolyline,
LIcon,
LGridLayer
} from "vue2-leaflet";
export default {
name: "Map",
components: {
LMap,
LTileLayer,
LMarker,
LImageOverlay,
LPopup,
LPolyline,
LIcon,
LGridLayer
},
props: {
msg: {
type: String
}
},
data() {
return {
url: "https://wallpaperboat.com/wp-content/uploads/2019/10/high-resolution-black-background-08.jpg",
bounds: [
[-2600, -2700],[1000, 3000]
],
minZoom: 0.5,
crs: L.CRS.Simple,
stars: [],
messageList: [],
tileComponent: {
name: "tile-component",
props: {
coords: {
type: Object,
required: true
}
},
template: '<div style="outline:1px solid #38c9d386; height:40rem; width:40rem;"></div>'
}
};
},
watch: {
msg: function() {
this.messageList.push(this.msg);
}
},
mounted() {
this.$refs.map.mapObject.setView([526, -68], 1);
this.$http
.get("https://pyet2m3rzl.execute-api.us-east-1.amazonaws.com/test/outscapebackend")
.then(response => {
return response.json();
})
.then(data => {
const resultArray = [];
for (let key in data) {
resultArray.push(data[key]);
}
this.stars = resultArray;
});
},
methods: {}
};
</script>
<style scoped>
...
</style>
如果我没理解错的话,你想反转所有 L.LatLng
的 Y 坐标,而不仅仅是图块坐标(这是 TMS 用例),这样Y 坐标在 向下 时增长。换句话说,如果我有类似...
L.marker([0,0]).addTo(map).bindPopup('y=0,x=0', {autoClose:false}).openPopup();
L.marker([100,50]).addTo(map).bindPopup('y=100,x=50', {autoClose:false}).openPopup();
...默认值看起来像...
...但您希望它看起来像...
(如果Y坐标在L.LatLng
的shorthand形式中排在第一位,请重新阅读Leaflet tutorial on L.CRS.Simple where the issue is explained, as well as lon lat lon lat lon)。
关于 Leaflet 内部的一些解释:Leaflet CRS 将 LatLng
坐标转换为像素坐标。例如默认L.CRS.EPSG3857
,屏幕Y坐标根据纬度的余弦得到traverse cylindrical projection.
对于 L.CRS.Simple
也存在这种翻译,因为存在古怪的差异。对于数学家来说,Y 坐标向上 因为这就是 cartesian plane 的工作原理:
但是,对于计算机程序员来说,Y 坐标会向下,因为屏幕上 that's how pixels are indexed(至少,几十年来一直是惯例):
为了解决这个问题,Leaflet 实现 affine transformations (which take into account the Leaflet quirks for zoom levels), and then L.CRS.Simple
使用这样的仿射变换来反转 Y 坐标(因此 L.CRS.Simple
就像笛卡尔平面而不是像素平面):
L.CRS.Simple = L.Util.extend({}, L.CRS, {
projection: L.Projection.LonLat,
transformation: L.Transformation(1, 0, -1, 0),
/* snip */
这相当于指定一个affine transformation matrix like
( 1 0 )
( 0 -1 )
因此,考虑到这一点,您的问题的答案变为 "you should define a new CRS with a custom affine transformation that maps 1 unit of «latitude» into 1 downwards pixel"。
此时,您应该阅读 Leaflet tutorial on extending Leaflet classes,但它的 TL;DR 版本是:
var CRSPixel = L.Util.extend(L.CRS.Simple, {
transformation: new L.Transformation(1,0,1,0)
});
然后将传递该自定义 CRS 的地图定义为地图的 crs
选项,然后一切正常。 Here's a working example with vanilla Leaflet(即无 vue)
有了这些信息,您应该能够使该技术适应您的 Vue 代码,稍微注意 import
所有需要的 Leaflet 位。