最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Invert Y axis of L:CRS.Simple map on Vue2-Leaflet - Stack Overflow

programmeradmin1浏览0评论

I am developing a map application using L.CRS.Simple of Vue2-Leaflet, and I want to invert the y-axis of my map as explained in the Leaflet documentation. I found a similar question here, and it seems my problem is the same, so my question is: how do I integrate the same solution that inverts the y-axis but using the vue2-leaflet package?

This is my code:

<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-ponent="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=".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",
  ponents: {
    LMap,
    LTileLayer,
    LMarker,
    LImageOverlay,
    LPopup,
    LPolyline,
    LIcon,
    LGridLayer
  },
  props: {
    msg: {
      type: String
    }
  },
  data() {
    return {
      url: ".jpg",
      bounds: [
        [-2600, -2700],[1000, 3000]
      ],
      minZoom: 0.5,
      crs: L.CRS.Simple,
      stars: [],
      messageList: [],
      tileComponent: {
        name: "tile-ponent",
        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("")
      .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>

I am developing a map application using L.CRS.Simple of Vue2-Leaflet, and I want to invert the y-axis of my map as explained in the Leaflet documentation. I found a similar question here, and it seems my problem is the same, so my question is: how do I integrate the same solution that inverts the y-axis but using the vue2-leaflet package?

This is my code:

<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-ponent="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./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",
  ponents: {
    LMap,
    LTileLayer,
    LMarker,
    LImageOverlay,
    LPopup,
    LPolyline,
    LIcon,
    LGridLayer
  },
  props: {
    msg: {
      type: String
    }
  },
  data() {
    return {
      url: "https://wallpaperboat./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-ponent",
        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./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>

Share Improve this question asked Jun 10, 2020 at 13:51 Ariana RubíAriana Rubí 9312 bronze badges 4
  • Do you want to invert the Y axis for the tile display, or for the coordinates? Those are different things. – IvanSanchez Commented Jun 10, 2020 at 14:33
  • As far as I understand, for L.CRS.Simple the Y coordinate is inverted, so the first top-right image's location is 1x-1 instead of 1x1. Therefore, I should only invert the Y axis for the tile display. I also understand that I need to create a subclass for the L.TileLayer, but my problem is that I am not managing to do that using the vue2-leaflet package :( @IvanSanchez – Ariana Rubí Commented Jun 10, 2020 at 17:59
  • The axis order in L.LatLngs is easting-northing: Y coordinates (latitude) grow larger when going north (on L.CRS.EPSG3857) and also grow larger when going up (on L.CRS.Simple). The Y tile coordinate in default L.TileLayers goes south or down but it goes north/up in TMS. Therefore, it's unclear whether you want to invert the Y coordinate in your CRS (so the axis order is easting-southing and "latitude" grows down) or just the tile coordinates. – IvanSanchez Commented Jun 10, 2020 at 18:17
  • 1 then yes, I need to invert the Y coordinate in my CRS, so the latitude grows down – Ariana Rubí Commented Jun 10, 2020 at 18:55
Add a ment  | 

1 Answer 1

Reset to default 11

If I'm understanding this right, you want to invert the Y coordinate of all L.LatLngs, and not just the tile coordinates (which is the TMS use case), so that Y coordinates grow when going down. In other words, if I have something like...

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();

...the default looks like...

...but you want it to look like...

(If the fact that the Y coordinate is listed first in the shorthand form of L.LatLngs, re-read the Leaflet tutorial on L.CRS.Simple where the issue is explained, as well as lon lat lon lat lon).

A bit of explanation about the Leaflet internals: a Leaflet CRS translates LatLng coordinates into pixel coordinates. e.g. in the default L.CRS.EPSG3857, the screen Y coordinate depends on the cosine of the latitude to get a traverse cylindrical projection.

With L.CRS.Simple this translation also exists, because of a quirky disparity. For mathematicians, the Y coordinate goes up because that's how a cartesian plane works:

However, for puter programmers, the Y coordinate goes down because that's how pixels are indexed on screens (at least, that's been the convention for decades):

In order to get around this quirk, Leaflet implements affine transformations (which take into account the Leaflet quirks for zoom levels), and then L.CRS.Simple uses such an affine transformation to invert the Y coordinate (so L.CRS.Simple works like a cartesian plane instead of a pixel plane):

L.CRS.Simple = L.Util.extend({}, L.CRS, {
    projection: L.Projection.LonLat,
    transformation: L.Transformation(1, 0, -1, 0),
    /* snip */

This is equivalent to specifying an affine transformation matrix like

( 1  0 )
( 0 -1 )

So, with this in mind, the answer to your question bees "you should define a new CRS with a custom affine transformation that maps 1 unit of «latitude» into 1 downwards pixel".

At this point, you should read the Leaflet tutorial on extending Leaflet classes, but the TL;DR version of that is:

var CRSPixel = L.Util.extend(L.CRS.Simple, {
    transformation: new L.Transformation(1,0,1,0)
});

Then define the map passing that custom CRS as the map's crs option, and everything should work. Here's a working example with vanilla Leaflet (i.e. vue-less)

With this information, you should be able to adapt the technique to your Vue code, taking a bit of care to import all the needed Leaflet bits.

发布评论

评论列表(0)

  1. 暂无评论