vue-leaflet / Vue2Leaflet

Vue 2 components for Leaflet maps
https://vue2-leaflet.netlify.app
MIT License
1.96k stars 380 forks source link

L.Icon.Default errors using vue-loader and webpack | Duplicated Marker #28

Closed jteppinette closed 5 years ago

jteppinette commented 7 years ago

System Information | Affected Versions

leaflet: 1.0.3
vue2-leaflet: 0.0.47
vue: 2.2.6
chrome: 58.0.3029.81 (64-bit)

Description

In v.0.0.47, I have noticed an issue with the Marker component being duplicated/shadowed when rendered in the map.

Code

<v-map :zoom=15 :center="[organization.latitude, organization.longitude]">
    <v-tilelayer :token="mapboxAPIKey" url="https://api.mapbox.com/v4/mapbox.streets/{z}/{x}/{y}.png?access_token={token}"></v-tilelayer>
    <v-marker :lat-lng="{'lat': organization.latitude, 'lng': organization.longitude}">
        <v-popup :content="organization.name"></v-popup>
    </v-marker>
</v-map>

edit: fixed code copy paste error

Fix

If I remove the transform: translate3d(395px, 200px, 0px) style from the img.leaflet-marker-icon, then the issue is resolved.

Edit: This change seems to move the "clickable" marker out of the pane, so it cannot be used as the trigger for a popup. The incorrect "fat" marker is the one that remains. I will look into other possible "full" resolutions.

Attachments

screen shot 2017-04-28 at 4 47 52 pm
KoRiGaN commented 7 years ago

Hi @jteppinette,

I can't reproduce this issue. Here is a link to my attempt to reproduce it. If you can contribute to it to reproduce it that would be great !

In you example, I noticed you close v-tilelayer twice, and put v-marker inside it. Marker should be added to map not tile layer.

<v-map :zoom=15 :center="[organization.latitude, organization.longitude]">
    <v-tilelayer :token="mapboxAPIKey" url="https://api.mapbox.com/v4/mapbox.streets/{z}/{x}/{y}.png?access_token={token}"></v-tilelayer>
        <v-marker :lat-lng="{'lat': organization.latitude, 'lng': organization.longitude}">
            <v-popup :content="organization.name"></v-popup>
        </v-marker>
    </v-tilelayer>
</v-map>

Micka

jteppinette commented 7 years ago

@KoRiGaN Thanks for taking a look at this. I have fixed the copy/paste mistake you noticed in my issue description.

I have tried to recreate this issue in the fiddle, but I have been unable to. Do you know what would cause this to be happening locally? The main differences between the fiddle and my local instance is webpack and vuetify. I tried wrapping your fiddle with the vuetify components I am using, but I still couldn't recreate the issue.

jteppinette commented 7 years ago

If I set display:none on leaflet-pane leaflet-shadow-pane, the incorrect marker will disappear.

KoRiGaN commented 7 years ago

I'm using webpack without any issue. I don't use vuetify at the moment.

Did you find out what caused this issue ?

MichalKrakow commented 7 years ago

I've setup my project using laravel mix (basically webpack with some extra config on top of it) the shadow image url is: http://localhost:3000/images/vendor/leaflet/dist/marker-icon.png?2273e3d8ad9264b7daa5bdbf8e6b47f8&quot;)marker-shadow.png so it uses the icon as shadow :).

With this level of f.ups i think webpack will not be here for very long. So if it looks familiar to someone please throw a hint.

jteppinette commented 7 years ago

Okay, interesting find. Yeah, my marker icons are being brought in as the following:

http://localhost:8080/assets/images/marker-icon.png?2273e3d8ad9264b7daa5bdbf8e6b47f8%22)marker-icon-2x.png
http://localhost:8080/assets/images/marker-icon.png?2273e3d8ad9264b7daa5bdbf8e6b47f8%22)marker-shadow.png

However, the Chrome preview shows them as being the same image. And, node_modules/leaflet/dist/images clearly shows marker-icon.png marker-shadow.png.

The url encoded characters %22) are "), so it looks like there could be some javascript runoff into the image urls.

jteppinette commented 7 years ago

Okay, I found where the Leaflet people are discussing this issue with webpack: https://github.com/Leaflet/Leaflet/issues/4968

They proposed this solution:

delete L.Icon.Default.prototype._getIconUrl;

L.Icon.Default.mergeOptions({
  iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
  iconUrl: require('leaflet/dist/images/marker-icon.png'),
  shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});
jteppinette commented 7 years ago

@MichalKrakow @KoRiGaN

I can confirm that my issue has been fixed by adding the following code to one of my single file components:

import L from 'leaflet';

L.Icon.Default.imagePath = '/';
L.Icon.Default.mergeOptions({
    iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
    iconUrl: require('leaflet/dist/images/marker-icon.png'),
    shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});

I assume that this would break the normal browser use case if this change was made to the repo. Do ya'll think we should just close this ticket and leave it to the Leaflet/Webpack community to come up with a better fix on their ends?

Thanks a ton for the help guys!

MichalKrakow commented 7 years ago

with me: `import Vue2Leaflet from 'vue2-leaflet';

L.Icon.Default.imagePath = '.'; L.Icon.Default.mergeOptions({ iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'), iconUrl: require('leaflet/dist/images/marker-icon.png'), shadowUrl: require('leaflet/dist/images/marker-shadow.png'), });`

did the trick. Probably it's not best practise to keep relative path in js but it have to do for now.

KoRiGaN commented 7 years ago

Change this issue title to better describe the issue.

Mickaël

dewdad commented 7 years ago

I'm using Vue PWA template and the following does not work for me:

<template>
  <div class="map">
    <v-map :zoom=13 :center="[47.413220, -1.219482]">
      <v-tilelayer url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"></v-tilelayer>
      <v-marker :lat-lng="[47.413220, -1.219482]"></v-marker>
    </v-map>
  </div>
</template>

<script>
import Vue2Leaflet from 'vue2-leaflet'

L.Icon.Default.imagePath = ''; // '/' doesn't work either
L.Icon.Default.mergeOptions({
    iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
    iconUrl: require('leaflet/dist/images/marker-icon.png'),
    shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});

export default {
  components: {
    'v-map': Vue2Leaflet.Map,
    'v-tilelayer': Vue2Leaflet.TileLayer,
    'v-marker': Vue2Leaflet.Marker
  },
  name: 'hello'
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
@import "~leaflet/dist/leaflet.css";

div.map{
  width: 800px;
  height: 600px;
}
</style>

The inlined base64 image is is missing a quote and closing parenthesis or something. Has anyone solved this? Maybe a css override solution?

This is the rendered HTML for the marker:

<div class="leaflet-pane leaflet-marker-pane"><img src="/data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQVR4Aa1XA5BjWRTN2oW17d3YaZtr2962HUzbDNpjszW24mRt28p47v7zq/bXZtrp/lWnXr337j3nPCe85NcypgSFdugCpW5YoDAMRaIMqRi6aKq5E3YqDQO3qAwjVWrD8Ncq/RBpykd8oZUb/kaJutow8r1aP9II0WmLKLIsJyv1w/kqw9Ch2MYdB++12Onxee/QMwvf4/Dk/Lfp/i4nxTXtOoQ4pW5Aj7wpici1A9erdAN2OH64x8OSP9j3Ft3b7aWkTg/Fm91siTra0f9on5sQr9INejH6CUUUpavjFNq1B+Oadhxmnfa8RfEmN8VNAsQhPqF55xHkMzz3jSmChWU6f7/XZKNH+9+hBLOHYozuKQPxyMPUKkrX/K0uWnfFaJGS1QPRtZsOPtr3NsW0uyh6NNCOkU3Yz+bXbT3I8G3xE5EXLXtCXbbqwCO9zPQYPRTZ5vIDXD7U+w7rFDEoUUf7ibHIR4y6bLVPXrz8JVZEql13trxwue/uDivd3fkWRbS6/IA2bID4uk0UpF1N8qLlbBlXs4Ee7HLTfV1j54APvODnSfOWBqtKVvjgLKzF5YdEk5ewRkGlK0i33Eofffc7HT56jD7/6U+qH3Cx7SBLNntH5YIPvODnyfIXZYRVDPqgHtLs5ABHD3YzLuespb7t79FY34DjMwrVrcTuwlT55YMPvOBnRrJ4VXTdNnYug5ucHLBjEpt30701A3Ts+HEa73u6dT3FNWwflY86eMHPk+Yu+i6pzUpRrW7SNDg5JHR4KapmM5Wv2E8Tfcb1HoqqHMHU+uWDD7zg54mz5/2BSnizi9T1Dg4QQXLToGNCkb6tb1NU+QAlGr1++eADrzhn/u8Q2YZhQVlZ5+CAOtqfbhmaUCS1ezNFVm2imDbPmPng5wmz+gwh+oHDce0eUtQ6OGDIyR0uUhUsoO3vfDmmgOezH0mZN59x7MBi++WDL1g/eEiU3avlidO671bkLfwbw5XV2P8Pzo0ydy4t2/0eu33xYSOMOD8hTf4CrBtGMSoXfPLchX+J0ruSePw3LZeK0juPJbYzrhkH0io7B3k164hiGvawhOKMLkrQLyVpZg8rHFW7E2uHOL888IBPlNZ1FPzstSJM694fWr6RwpvcJK60+0HCILTBzZLFNdtAzJaohze60T8qBzyh5ZuOg5e7uwQppofEmf2++DYvmySqGBuKaicF1blQjhuHdvCIMvp8whTTfZzI7RldpwtSzL+F1+wkdZ2TBOW2gIF88PBTzD/gpeREAMEbxnJcaJHNHrpzji0gQCS6hdkEeYt9DF/2qPcEC8RM28Hwmr3sdNyht00byAut2k3gufWNtgtOEOFGUwcXWNDbdNbpgBGxEvKkOQsxivJx33iow0Vw5S6SVTrpVq11ysA2Rp7gTfPfktc6zhtXBBC+adRLshf6sG2RfHPZ5EAc4sVZ83yCN00Fk/4kggu40ZTvIEm5g24qtU4KjBrx/BTTH8ifVASAG7gKrnWxJDcU7x8X6Ecczhm3o6YicvsLXWfh3Ch1W0k8x0nXF+0fFxgt4phz8QvypiwCCFKMqXCnqXExjq10beH+UUA7+nG6mdG/Pu0f3LgFcGrl2s0kNNjpmoJ9o4B29CMO8dMT4Q5ox8uitF6fqsrJOr8qnwNbRzv6hSnG5wP+64C7h9lp30hKNtKdWjtdkbuPA19nJ7Tz3zR/ibgARbhb4AlhavcBebmTHcFl2fvYEnW0ox9xMxKBS8btJ+KiEbq9zA4RthQXDhPa0T9TEe69gWupwc6uBUphquXgf+/FrIjweHQS4/pduMe5ERUMHUd9xv8ZR98CxkS4F2n3EUrUZ10EYNw7BWm9x1GiPssi3GgiGRDKWRYZfXlON+dfNbM+GgIwYdwAAAAASUVORK5CYII=" class="leaflet-marker-icon leaflet-zoom-animated leaflet-interactive" tabindex="0" style="margin-left: -12px; margin-top: -41px; width: 25px; height: 41px; transform: translate3d(400px, 300px, 0px); z-index: 300;"></div>
bytebrain commented 7 years ago

I've got it working by deleting the _getIconUrl prototype first.

Here is my complete working component:

<template>
  <div>
    <v-map class="mini-map" :zoom=13 :center="[47.413220, -1.219482]">
      <v-tilelayer url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"></v-tilelayer>
      <v-marker :lat-lng="[47.413220, -1.219482]"></v-marker>
    </v-map>
  </div>
</template>

<script>
import L from 'leaflet'
import Vue2Leaflet from 'vue2-leaflet'

// Build icon assets.
delete L.Icon.Default.prototype._getIconUrl
L.Icon.Default.imagePath = ''
L.Icon.Default.mergeOptions({
  iconRetinaUrl: require('../assets/markers/marker-icon-2x.png'),
  iconUrl: require('../assets/markers/marker-icon.png'),
  shadowUrl: require('../assets/markers/marker-shadow.png')
})

export default {
  components: {
    'v-map': Vue2Leaflet.Map,
    'v-tilelayer': Vue2Leaflet.TileLayer,
    'v-marker': Vue2Leaflet.Marker
  }
}
</script>

<style lang="scss">
@import "~leaflet/dist/leaflet.css";

.mini-map {
  width:100%;
  height:250px !important;
}
</style>
KoRiGaN commented 7 years ago

PR Leaflet/Leaflet#5771 seems to be a fix for that kind of issue with webpack.

Wait and see.

zzhengzhu commented 6 years ago

I encountered the same problem. According to the quotes in leaflet.css file:

            // @option imagePath: String
    // `Icon.Default` will try to auto-detect the location of the
    // blue icon images. If you are placing these images in a non-standard
    // way, set this option to point to the right path.

Try add a imagePath string in the options object, like this:

           imagePath: 'images/vendor/leaflet/dist/'
tiangolo commented 5 years ago

There's now a plug-in, at the Leaflet level, to solve this: https://github.com/ghybs/leaflet-defaulticon-compatibility.

It's working well for me. And I'm also using Vue2Leaflet.

Maybe it's worth adding it to the docs?

DonNicoJs commented 5 years ago

closing here and adding a new issue to update the docs with the info collected in this thread