Leaflet: L.Icon.Default traz um url de imagem errado

Criado em 28 set. 2016  ·  90Comentários  ·  Fonte: Leaflet/Leaflet

  • [x] Estou relatando um bug, não estou pedindo ajuda
  • [] Eu olhei a documentação para ter certeza de que o comportamento é documentado e esperado
  • [x] Tenho certeza de que é um problema de código de folheto, não um problema com meu próprio código nem com a estrutura que estou usando (Cordova, Ionic, Angular, React ...)
  • [] Pesquisei os problemas para ter certeza de que ainda não foram relatados

O folheto da url da imagem que me apresenta é https://uismedia.geo-info-manager.com/apis/leaflet_1/imagesmarker-icon-2x.png. Parece que falta um "/"
Além disso, eu tenho um erro
leaflet.min.js: 5 GET https://uismedia.geo-info-manager.com/apis/leaflet_1/images/ 403 (Proibido)

compatibility

Comentários muito úteis

Queria compartilhar o que fiz para contornar o problema de dados inválidos

import L from 'leaflet';

import icon from 'leaflet/dist/images/marker-icon.png';
import iconShadow from 'leaflet/dist/images/marker-shadow.png';

let DefaultIcon = L.icon({
    iconUrl: icon,
    shadowUrl: iconShadow
});

L.Marker.prototype.options.icon = DefaultIcon;

Provavelmente poderia ser ajustado para incluir o ícone da retina também.

Todos 90 comentários

  • Existe alguma página da Web pública em seu servidor que possamos visitar, para que possamos reproduzir o problema nós mesmos?
  • Qual sistema operacional e navegador da web você está usando?

leaflet.min.js: 5 GET https://uismedia.geo-info-manager.com/apis/leaflet_1/images/ 403 (Proibido)

Isso pode ser o mesmo problema discutido em https://github.com/Leaflet/Leaflet/issues/4849

De fato. Por isso estou curioso para saber em que circunstâncias isso pode ser reproduzido, para que possamos fazer testes de unidade com elas.

Tive o mesmo problema ao mudar de RC3 para 1.0.1 - em meu código, tinha a linha L.Icon.Default.imagePath = 'images'; - não me lembro bem por que isso aconteceu, mas comentá-lo resolveu o problema - pode valer a pena verificar se você não tem um semelhante

de repente teve o mesmo problema em dois projetos completamente diferentes, ambos usando webpack e folheto.
Se eu adicionar marcadores ao mapa, as imagens não serão encontradas. O navegador gera este erro:
image

ok eu tenho algo.

Portanto, um marcador se parece com este atualmente porque as imagens (ícone e sombra) não foram encontradas.
image

esta função no folheto:

_getIconUrl: function (name) {
    if (!L.Icon.Default.imagePath) {    // Deprecated, backwards-compatibility only
        L.Icon.Default.imagePath = this._detectIconPath();
    }

    // <strong i="10">@option</strong> imagePath: String
    // `L.Icon.Default` will try to auto-detect the absolute 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 absolute path.
    return (this.options.imagePath || L.Icon.Default.imagePath) + L.Icon.prototype._getIconUrl.call(this, name);
},

faz com que os data:image urls tenham a seguinte string no final do url:
")marker-icon-2x.png .

O nome do arquivo pode ser removido se você excluir + L.Icon.prototype._getIconUrl.call(this, name) . A parte ") é provavelmente da mágica de _detectIconPath regex. Não consigo consertar isso, então tentei cortar os dois últimos caracteres, o que resulta nesta função:

_getIconUrl: function (name) {
    if (!L.Icon.Default.imagePath) {    // Deprecated, backwards-compatibility only
        L.Icon.Default.imagePath = this._detectIconPath();
    }

    // <strong i="21">@option</strong> imagePath: String
    // `L.Icon.Default` will try to auto-detect the absolute 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 absolute path.
  var url = (this.options.imagePath || L.Icon.Default.imagePath);

  return url.slice(0, - 2);
},

e aqui vamos nós, o ícone aparece. Um último problema é que a imagem de sombra também é um ícone de marcador - o caminho src já está errado, não tenho ideia do porquê (ainda). Portanto, um marcador agora se parece com este:

image

@IvanSanchez isso ajuda a restringir um pouco o problema?

@codeofsumit seria bom passar por _detectIconPath e ver o que está acontecendo lá, especialmente qual valor a variável path tem antes de passar pela regex.

@IvanSanchez @perliedman Acho que encontrei o bug.

Este é _detectIconPath

_detectIconPath: function () {
    var el = L.DomUtil.create('div',  'leaflet-default-icon-path', document.body);
    var path = L.DomUtil.getStyle(el, 'background-image') ||
               L.DomUtil.getStyle(el, 'backgroundImage');   // IE8
    document.body.removeChild(el);

    return path.indexOf('url') === 0 ?
        path.replace(/^url\([\"\']?/, '').replace(/marker-icon\.png[\"\']?\)$/, '') : '';
}

a variável path é algo assim:
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQ…n3EUrUZ10EYNw7BWm9x1GiPssi3GgiGRDKWRYZfXlON+dfNbM+GgIwYdwAAAAASUVORK5CYII=") .

Qual é correto.

Agora, a regex deseja extrair o url data.image disso e retorna o seguinte:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQ…n3EUrUZ10EYNw7BWm9x1GiPssi3GgiGRDKWRYZfXlON+dfNbM+GgIwYdwAAAAASUVORK5CYII=")

Observe o último ") que não foi removido da variável path . A regex /^url\([\"\']?/ visa apenas url(" no início do caminho, não ") no final.
Usar esta regex funciona:

return path.indexOf('url') === 0 ?
    path.replace(/^url\([\"\']?/, '').replace(/\"\)$/, '').replace(/marker-icon\.png[\"\']?\)$/, '') : '';

Isso corrige o problema da imagem, junto com

var url = (this.options.imagePath || L.Icon.Default.imagePath);

dentro de _getIconUrl . Mas isso não corrige a sombra - eu ainda não sei o que está acontecendo com a sombra.

tendo o mesmo problema,
o valor do caminho em _detectIconPath é algo como "url (" data: image / png; base64, i ... 5CYII = ")"
e parece que _getIconUrl e _detectIconPath não foram projetados para lidar com URLs de dados

o problema da sombra parece ser causado pelo fato de que em _getIconUrl o valor de L.Icon.Default.imagePath já está definido com o URL de dados do marcador, então a imagem do marcador é usada e esticada
image

poderia estar relacionado a este commit codificando a imagem do marcador?
https://github.com/Leaflet/Leaflet/commit/837d19093307eb5eeb1fca6536962a1ab1573dd5

@ Radu-Filip Consegui consertar com essas modificações no seu PR - não tenho certeza de que outros efeitos isso pode ter:
image

O problema é - como você disse - que o URL padrão é a imagem do marcador, basicamente para todos os ícones.
Então, antes de mais nada, adicionei o URL padrão da sombra ao CSS:

/* Default icon URLs */
.leaflet-default-icon-path {
    background-image: url(images/marker-icon.png);
}

.leaflet-default-shadow-path {
    background-image: url(images/marker-shadow.png);
}

Em seguida, passei o nome de _getIconUrl para _detectIconPath e usei-o para adicionar a classe ao elemento do qual o caminho é extraído:

_getIconUrl: function (name) {

  L.Icon.Default.imagePath = this._detectIconPath(name);

    // <strong i="15">@option</strong> imagePath: String
    // `L.Icon.Default` will try to auto-detect the absolute 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 absolute path.
  var path = this.options.imagePath || L.Icon.Default.imagePath;
  return path.indexOf("data:") === 0 ? path : path + L.Icon.prototype._getIconUrl.call(this, name);
},

_detectIconPath: function (name) {
    var el = L.DomUtil.create('div',  'leaflet-default-' + name + '-path', document.body);
    var path = L.DomUtil.getStyle(el, 'background-image') ||
               L.DomUtil.getStyle(el, 'backgroundImage');   // IE8

    document.body.removeChild(el);

    return path.indexOf('url') === 0 ? path.replace(/^url\([\"\']?/, '').replace(/(marker-icon\.png)?[\"\']?\)$/, '') : '';
}

Eu também tive que remover o if / else em torno de detectIconPath , porque não foi chamado para o ícone de sombra. Agora tudo funciona para o ícone do marcador padrão - não tenho certeza sobre os personalizados.

@codeofsumit sim, eu fiz algo semelhante aqui https://github.com/Radu-Filip/Leaflet/tree/temp
e vou usá-lo por enquanto como um hack. Esperançosamente, haverá uma solução mais preparada para o futuro no futuro para aqueles que usam o webpack et al

@ Radu-Filip, você se importa em atualizar seu RP com essa solução? Ele pode ser mesclado.

@codeofsumit pronto, vamos ver se passa

Oi,

Talvez eu sinta falta de algo, mas me parece que esse problema de construção do Webpack poderia ser simplesmente resolvido com um plug-in do Leaflet, que substituiria o comportamento de L.Icon.Default .

Demonstração: http://playground-leaflet.rhcloud.com/nexo/1/edit?html , css, output

Com essa abordagem, você se livra de qualquer RegExp complicado e as imagens do marcador padrão são embutidas (por codificação permanente), o que é um dos resultados pretendidos do Webpack para imagens pequenas.

Uma possível desvantagem é que cada marcador tem seu próprio ícone base64, não tenho certeza se os navegadores podem armazenar isso em cache ... (mesma desvantagem para PR # 5041)
Poderíamos imaginar um refinamento definindo-o como uma imagem de fundo em vez de colocá-lo no atributo src , como feito para o ícone de controle de camadas, por exemplo.
Pode haver uma armadilha oculta com esta ideia (editar: parece que esse aqui ), caso contrário, tenho certeza que teria sido implementado há muito tempo, pois teria evitado a detecção do caminho da imagem em primeiro lugar.

Demonstração: http://playground-leaflet.rhcloud.com/mey/1/edit?html , css, saída (sem cuidar da retina)

A maior vantagem da abordagem do plugin é que ele mantém esse comportamento específico apenas para projetos Webpack.

Espero que isto ajude.

BTW, parece-me que há algo intrinsecamente errado aqui.

O folheto faz uma detecção "complexa" de caminhos para as imagens, que devem estar em um local pré-definido em comparação com o arquivo CSS.

Mas o processo de construção do webpack agrupa esse CSS e pode (ou não) mover as imagens também (e renomeá-las!), Dependendo do que o desenvolvedor solicitar ao webpack (como exigir imagens).
Portanto, a detecção do folheto certamente falha quando o webpack é usado.

PR # 5041 é como um truque para aceitar o caso em que webpack inline imagens no CSS, ao custo de duplicar a imagem Base64 em cada marcador. Nem mesmo falando sobre o custo para usuários que não usam webpack.

PR # 4979 foi feito apenas para evitar a mensagem de erro de construção do webpack (devido à falta de arquivo), ele não parece lidar com a resolução real do caminho da imagem.
Eu acho que os desenvolvedores então especificam manualmente o L.Icon.Default.imagePath ?
@jasongrout e @Eschon , talvez você pudesse compartilhar como você conseguiu isso?

Eu realmente não consigo. Eu simplesmente não uso o ícone padrão, então esse bug não foi um problema para mim até agora.

Olá, apenas uma nota para dizer que posso reproduzir esse erro de caminho usando a versão 1.0.1 desta biblioteca.
Estou usando junto com o folheto do módulo Drupal (7.x-1.x-dev), e aqui há um problema relatado ao módulo: https://www.drupal.org/node/2814039 caso seja útil.

Tanto quanto posso ver o "problema" está na função _getIconUrl? pois depois de L.Icon.Default.imagePath falta uma barra, então o caminho da imagem, por exemplo no Drupal, é gerado como "/ sites / all / libraries / leaflet / imagesmarker-icon.png ". Entre o caminho das imagens e o nome do arquivo da imagem do marcador (marker-icon.png) deve haver uma barra /.

Olá @ anairamzap-mobomo,

Parece que o que você relata é um problema diferente.

Infelizmente, como parece envolver uma porta para um framework (Drupal), você deve primeiro se certificar de que o bug não está relacionado ao funcionamento dessa porta.

O folheto 1.0.x com vanilla JS inclui corretamente a barra final: http://playground-leaflet.rhcloud.com/fosa/1/edit?html , saída

Veja, por exemplo, http://cgit.drupalcode.org/leaflet/tree/leaflet.module#n51 , onde L.Icon.Default.imagePath é substituído pelo módulo Drupal.

Parece que esse módulo não lida com a mudança entre o Leaflet 0.7.xe 1.0.x, onde a barra agora deve ser incluída em L.Icon.Default.imagePath .

Como o Leaflet 1.0.0 é uma versão principal, acho que não há compromisso de compatibilidade com versões anteriores.

hey @ghybs entendo ... Vou entrar em contato com os mantenedores do módulo Drupal para informá-los disso. Como você disse, parece que eles têm que modificar o módulo para se ajustar bem à versão 1.0.x da biblioteca, ou pelo menos adicionar algumas linhas aos documentos alertando sobre isso.

Obrigado pelo seu feedback!

Estou tendo exatamente o mesmo problema relatado originalmente - em um projeto aurulia skeleton / esnext + webpack.

Até que isso seja corrigido, copiei as imagens para minha pasta de origem e estou usando um marcador personalizado - omitir as informações de tamanho / posicionamento parece estar ok ...

        var customDefault = L.icon({
            iconUrl: 'images/marker-icon.png',
            shadowUrl: 'images/marker-shadow.png',
        });

Queria compartilhar o que fiz para contornar o problema de dados inválidos

import L from 'leaflet';

import icon from 'leaflet/dist/images/marker-icon.png';
import iconShadow from 'leaflet/dist/images/marker-shadow.png';

let DefaultIcon = L.icon({
    iconUrl: icon,
    shadowUrl: iconShadow
});

L.Marker.prototype.options.icon = DefaultIcon;

Provavelmente poderia ser ajustado para incluir o ícone da retina também.

alguém poderia enviar o arquivo leaflet.js modificado?
o código que @ ajoslin103 está usando:
`` `var customDefault = L.icon ({
iconUrl: 'images / marker-icon.png',
shadowUrl: 'images / marker-shadow.png',
});

Não modifiquei o arquivo leaflet.js, apenas copiei as imagens do marcador da distribuição do folheto para minha pasta de imagens normal e usei aquele fragmento que postei como um ícone personalizado.

Não consegui usar a solução do crob611 porque eles eram referenciados no css original como http e meu site estava sendo servido por https.

`` `function onLocationFound (e) {
raio var = e.accuracy / 2;
var customDefault = L.icon ({
iconUrl: 'marker_icon_2x',
shadowUrl: 'marker_shadow.png'
});
L.marker (e.latlng) .addTo (mapa)
.bindPopup ("Você está dentro de" + raio + "metros deste ponto"). openPopup ();
L.circle (e.latlng, radius) .addTo (map);
}

como posso definir o novo ícone?

Eu crio o ícone personalizado no meu construtor (estou usando a estrutura Aurelia)

        this.customDefault = L.icon({
            iconUrl: 'images/marker-icon.png',
            shadowUrl: 'images/marker-shadow.png',
        });

Então eu o uso quando adiciono o marcador no método attach ()

        var map = L.map('mapid').setView([latitude, longitude], 13);
        let urlTemplate = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png';
        map.addLayer(L.tileLayer(urlTemplate, { minZoom: 4 }));
        L.marker([latitude, longitude], { icon: this.customDefault }).addTo(map);

Ref: http://leafletjs.com/examples/custom-icons/

Até que haja uma boa solução para esse problema, sugiro adicionar um aviso de tempo de execução quando _getIconUrl() (ou qualquer outro) encontrar inesperadamente uma IU de dados, apontando para um URL de problema do Github por meio de console.warn ou algo assim Curtiu isso.

Isso levaria pessoas com o mesmo problema ao lugar certo e sugeriria soluções alternativas (como esta que funcionou para mim).

É assim que o React (dev builds) ajuda os desenvolvedores a identificar problemas.

Do problema de reação, uma solução alternativa por @PTihomir

import L from 'leaflet';
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'),
});

isso corrige o problema sem uma alteração nos arquivos principais do folheto.

@codeofsumit : Para sua informação, pelo que entendi, esta solução alternativa funciona apenas para os três ícones mencionados.

A solução alternativa precisará ser ajustada caso o Leflet exija (ou exigirá no futuro) outros ícones de maneira semelhante (talvez para outros componentes - não sei).


Para quem não está familiarizado com Webpack: Webpack atribuirá novos URLs a estas propriedades:

/***/ 5305024559067547:
/***/ function(module, exports, __webpack_require__) {

    module.exports = __webpack_require__.p + "d95d69fa8a7dfe391399e22c0c45e203.png";

/***/ },


...


    _leaflet2['default'].Icon.Default.mergeOptions({
      iconRetinaUrl: __webpack_require__(5305024559067547),
      iconUrl: __webpack_require__(6633266380715105),
      shadowUrl: __webpack_require__(880063406195787)
    });

(os detalhes dependem muito da configuração do Webpack usada)

@jampy sim, claro. Portanto, é uma solução alternativa. Quaisquer modificações no núcleo do folheto, no entanto, serão excluídas a cada atualização, independentemente. Vou usar a solução alternativa mencionada até que haja uma correção adequada, pois parece o menos doloroso.

Mesmo problema aqui, a função detectIconPath retorna http://localhost:8080/2273e3d8ad9264b7daa5bdbf8e6b47f8.png") para o caminho url("http://localhost:8080/2273e3d8ad9264b7daa5bdbf8e6b47f8.png")

está longe de ser o ideal, mas eu uso o webpack e uso esta solução alternativa

Copiei as imagens para uma pasta de imagens na raiz do meu projeto

em seguida, em meu package.json, adicionei um script npm postbuild (na seção de scripts)
" postbuild: prod ": "./Post-Build4Prod.sh"

que copia uma pasta de imagens para o dist

#bin/bash
cp -r ./images ./dist/.

então eu defino um padrão personalizado para ícones

    this.customDefault = L.icon({
        iconUrl: 'images/marker-icon.png',
        shadowUrl: 'images/marker-shadow.png',
    });

e use isso em qualquer lugar

    L.marker([latitude, longitude], { icon: this.customDefault }).addTo(map);

@ ajoslin103 , considere esta solução alternativa . É mais simples e você acaba com o mesmo resultado.

Usei o seguinte para contornar isso em um projeto de webpack do Vue:

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'),
});

Eu tive o mesmo problema com Django's collectstatic e CachedStaticFilesStorage que adiciona um hash do conteúdo do arquivo ao nome de arquivos estáticos, então marker-icon.png torna-se marker-icon.2273e3d8ad92.png e então regexp no final de _detectIconPath falha em corresponder.

Eu mudei para replace(/marker-icon[^"']+\.png[\"\']?\)$/, '') que funcionou para mim.

Eu também tenho esse problema atualmente.
Usando o folheto 1.0.3 e o Angular2.
Confesso que não vejo como resolver neste tópico.

Para Angular 2 e 4
Crio um arquivo require.d.ts com o código:

interface WebpackRequire {
    <T>(path: string): T;
    (paths: string[], callback: (...modules: any[]) => void): void;
    ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
}
interface NodeRequire extends WebpackRequire {}
declare var require: NodeRequire;

e então usando requerpara este problema:

                  this.marker = L.marker(e.latlng, {
                    icon: L.icon({
                        iconUrl: require <any>('../../images/marker-icon.png'),
                        shadowUrl: require <any>('../../images/marker-shadow.png'),
                    })

Solução alternativa (com tamanho e âncora) para Vue.js com webpack :

import L from 'leaflet'

// BUG https://github.com/Leaflet/Leaflet/issues/4968
import iconRetinaUrl from 'leaflet/dist/images/marker-icon-2x.png'
import iconUrl from 'leaflet/dist/images/marker-icon.png'
import shadowUrl from 'leaflet/dist/images/marker-shadow.png'
L.Marker.prototype.options.icon = L.icon({
  iconRetinaUrl,
  iconUrl,
  shadowUrl,
  iconSize: [25, 41],
  iconAnchor: [12, 41],
  popupAnchor: [1, -34],
  tooltipAnchor: [16, -28],
  shadowSize: [41, 41]
})

Fiz alguns testes rápidos de desempenho para embutir o ícone padrão como base64 em vez de usar um URL de imagem externa. Ao carregar _muitos_ marcadores (1000, no meu caso), o desempenho é notavelmente pior para imagens embutidas de base64.

Esta é a visualização de desempenho do Chrome Devtools ao carregar 1.000 ícones de marcadores como URLs externos:

1000 markers icons as external URLs

Em comparação, com 1000 ícones de marcador como base64 embutida (observe a escala diferente para a linha do tempo, desculpe):

1000 markers icons as inlined base64 URLs

Como pode ser visto, por algum motivo a composição da camada é atrasada ao usar imagens embutidas, o que faz com que toda a carga demore cerca de um segundo a mais.

Para uso casual, isso provavelmente não importa, mas se você usar muitos marcadores, isso pode ser relevante.

Uma proposta de como lidar com esse longo prazo:

  • Corrija # 5041 para resolver os problemas mencionados na revisão do código; isso faria os ícones embutidos funcionarem fora da caixa
  • Registre um aviso se ícones embutidos forem usados, para indicar que isso pode não ser o ideal

Outra opção seria reverter para o método antigo (0,7) de detecção do caminho da imagem, mas sabemos que havia outros problemas que não pudemos resolver.

Olá @perliedman ,

Bom perfil!
Ele responde às dúvidas que eu tinha sobre o lado negativo da reutilização de imagens embutidas.

Na verdade, o PR # 5041 pode ser refatorado para que o Leaflet funcione imediatamente quando as imagens dos ícones forem inseridas no CSS (por um mecanismo de construção como o webpack).
A solução que consigo pensar (em grande parte semelhante ao PR mencionado) implicaria na criação de 1 classe por imagem, portanto, aumentaria o tamanho do arquivo CSS (e provavelmente JS) em algumas dezenas de bytes.

Exemplo: http://playground-leaflet.rhcloud.com/dulox/1/edit?html , css, output

Mas, como mencionei anteriormente , é lamentável que tal mudança por motivos de compatibilidade (com motores de compilação) afete os usuários que não usam essas estruturas e processos de compilação.

Por outro lado, o resultado poderia ser "mais limpo", pois poderíamos nos livrar dos nomes de arquivos embutidos em código nas opções de classe IconDefault e delegar o caminho completo (incluindo o nome do arquivo) ao CSS.
Isso é muito interessante porque (se bem entendi) o objetivo dessa detecção complexa é separar a localização das imagens do arquivo JS e, em vez disso, confiar em sua localização relativa ao arquivo CSS. Portanto, faz sentido para mim que até mesmo o nome do arquivo seja definido no CSS.

Mas tentar manter a compatibilidade com a opção imagePath também pode ser complicado, pois provavelmente exigiria o retrabalho dos caminhos da imagem que foram detectados anteriormente, para substituir o caminho principal e manter o nome do arquivo. Portanto, apresentaríamos um novo RegExp lá.

Finalmente, não tenho certeza se isso cobriria todos os casos.
Os processos de construção podem ser altamente personalizados, levando a situações muito diferentes em relação a ativos estáticos, como imagens de ícones. Ainda pode haver alguns casos extremos em que até mesmo o acima falharia.

@ghybs Gosto desse exemplo (http://playground-leaflet.rhcloud.com/dulox/)!

Talvez exagero, mas o que você acha de também especificar o ícone _size_ neste CSS (usando width e height )? Posso imaginar alguém substituindo essas regras CSS para alterar o ícone padrão, apenas para descobrir que agora ele tem as dimensões erradas.

Com ou sem as dimensões em CSS, acho que esse é um bom caminho a seguir. Você se importaria de fazer um PR seguindo as linhas do seu exemplo? Se você não tem tempo ou energia agora, posso ir em frente e fazer isso, apenas me diga o que você prefere.

Estou ansioso para encerrar este, já que, na verdade, eu mesmo me deparei com esse problema.

Olá @perliedman ,

Concordo que seria ainda melhor poder especificar o tamanho do ícone também por meio de CSS.

Mas, nesse caso, para consistência, também devemos ser capazes de especificar o ponto de ancoragem. Não tenho certeza de qual regra CSS seria adequada para isso (talvez margem?). Se isso for possível, o resultado seria muito bom, eu acho: os ícones seriam totalmente definidos em CSS.

Indo ainda mais longe, essa poderia ser uma maneira extra de definir um ícone: especifique 3 classes CSS (ícone, retina, sombra) e o folheto extrairá todas as opções de ícone delas.

Sinta-se à vontade para trabalhar nisso, não tenho certeza de quando terei algum tempo, infelizmente ...

Com base no exemplo anterior, aqui está um conceito de leitura de padding e margin regras CSS para determinar iconAnchor ( shadowAnchor ) e popupAnchor opções:
http://playground-leaflet.rhcloud.com/xuvi/1/edit?html , css, output

Não gostei do fato de ter usado padding para determinar o iconAnchor , porque no final do Folheto usei margin para posicionar a imagem do ícone…
Mas é mais fácil especificar coisas rapidamente em CSS e evitar a reversão de valores em comparação com a forma como especificamos as opções de ícone.

Embora eu goste do resultado de especificar tudo em CSS, ainda há mais trabalho necessário para manter a compatibilidade com versões anteriores de L.Icon.Default.imagePath .

Peço desculpas, não tenho tempo para criar um PR.

Acabei de diagnosticar outro caso em que _detectIconPath falha: Ao usar o Firefox (testado com ESR e versões atuais) e definir Preferências → Conteúdo → Cores… → Substituir as cores especificadas pela página com suas seleções acima: Sempre o Firefox irá remover background-image propriedades incluindo aquela em .leaflet-default-icon-path e, portanto, quebram _detectIconPath .

Não tenho certeza de quantas outras pessoas usam esse recurso do Firefox, mas já o uso há muito tempo.

url() ser usado como valor de outras propriedades CSS também? Como usar o seguinte CSS: .leaflet-default-icon-path { -leaflet-icon: url(images/marker-icon.png); } ou é impossível definir e usar propriedades CSS personalizadas sozinho? Nenhum navegador precisaria _compreender_ a propriedade -leaflet-icon ; no entanto, eles ainda precisariam preenchê-la e disponibilizar seu valor para scripts.

Olá @roques ,

Obrigado por relatar este problema ao usar esta opção específica no Firefox!
Parece que o Chrome tem uma extensão de Alto Contraste mas que só muda as cores, sem quebrar nada no Folheto.

Infelizmente, o Firefox remove as propriedades CSS que não entende.
No entanto, o tipo de dados CSS da cursor , que parece funcionar bem mesmo quando a configuração de substituição de cores é usada no Firefox:
http://playground-leaflet.rhcloud.com/yov/1/edit?html , css, output

Acho menos elegante usar cursor vez de background-image , já que seu uso é muito mais longe do que faríamos para criar um marcador por meio do estilo CSS ... mas, de qualquer forma, isso já é um hack para o caminho detecção apenas.

Eu estava prestes a fazer um PR para resolver o problema do webpack, vou incluir esta solução alternativa agora.
Não tenho ideia de como poderíamos fazer um teste automatizado para este caso, mas acho que a solução alternativa já deve ser boa.

Alguém encontrou uma solução clara para esse problema?

Com base na resposta de @ Shiva127 , para qualquer um que use Angular + Angular CLI:

Você pode colocar isso em app.module.ts :

// BUG https://github.com/Leaflet/Leaflet/issues/4968
import {icon, Marker} from 'leaflet';
const iconRetinaUrl = 'assets/marker-icon-2x.png';
const iconUrl = 'assets/marker-icon.png';
const shadowUrl = 'assets/marker-shadow.png';
const iconDefault = icon({
  iconRetinaUrl,
  iconUrl,
  shadowUrl,
  iconSize: [25, 41],
  iconAnchor: [12, 41],
  popupAnchor: [1, -34],
  tooltipAnchor: [16, -28],
  shadowSize: [41, 41]
});
Marker.prototype.options.icon = iconDefault;

e adicione a linha glob em seu .angular-cli.json :

"assets": [
        "assets",
        "favicon.ico",
        { "glob": "**/*", "input": "../node_modules/leaflet/dist/images/", "output": "./assets/" }
      ],

Isso copiará os ícones para a pasta de ativos na pasta dist no momento da construção (você não os verá em src / ativos). Além disso, colocar a solução em app.module.ts é um bom lugar para manter importações de modificação de protótipo global (como patches observáveis ​​RxJS). Com isso, importar o Marker em outro local da base de código funcionará corretamente.

Eu consertei esse problema assim.

Eu forneci um ícone padrão para marcar opções de desenho:

const myIcon = L.icon({
    ...
    ...
});

const drawOptions = {
      ....
      marker: {
         icon: myIcon
      }
};

...

Em seguida, salvou o caminho para o ícone em L.Draw.Event.CREATED

this.map.on(L.Draw.Event.CREATED, (e) => {

      const layer: any = (e as L.DrawEvents.Created).layer;
      const type = (e as L.DrawEvents.Created).layerType;

      // Create a marker.
      if (type === 'marker') {

        let feature = layer.feature = layer.feature || {};
        feature.type = "Feature";
        feature.properties = feature.properties || {};
        feature.properties["markerIconsPath"] = "/assets/icons/";
       }
 });


Finalmente, ao exibir as camadas, configurei imagePath:

if(layer instanceof L.Marker) {
            L.Icon.Default.imagePath = layer.feature.properties.markerIconsPath;
            layer.setIcon(greenIcon);
 }

@codeofsumit essas correções estão incluídas na última versão 1.3.1? Surpreendentemente, estou usando a versão 1.3.1 e ainda enfrento o mesmo problema.

@vishalrajole que eu saiba, o único PR enviado para abordar isso é o # 5041, que está aberto com as alterações solicitadas há _muito_.

Também temos a solução alternativa # 5771, que é boa, mas envolveu mais alterações.

Então, para resumir: ninguém enviou um PR aceito para resolver isso, ajuda é bem-vinda!

@perliedman pelo que parece, as alterações envolvidas de # 5771 são necessárias. Caso contrário, você continuará tendo esse problema em diferentes circunstâncias. Por que não apenas mesclar isso?

Olá @ mb21 ,

as alterações envolvidas de # 5771 são necessárias

Na verdade, as mudanças propostas são de 2 tipos:

  • ler cada caminho de imagem em vez de apenas o local da pasta de imagens, de modo que os urls modificados pelos mecanismos de construção (como o carregador de arquivos webpack) sejam lidos como estão, em vez de reconstruídos / adivinhados.
  • lendo todas as outras opções de ícone padrão do CSS, para que toda a configuração seja reunida em um único lugar.

O segundo ponto é interessante se o primeiro não puder ser evitado, mesmo que acrescente algum código.

O primeiro é, na verdade, um favor para os desenvolvedores que usam um mecanismo de compilação que mexe com urls em CSS. Ele mantém o _espirito de configuração zero_ do folheto, mesmo em um novo ambiente onde o desenvolvedor gasta algum tempo ajustando sua configuração (se você usar o carregador de arquivos webpack, você precisa de uma configuração personalizada de qualquer maneira), à custa de adicionar algum código para todos os outros, que é IMHO _against_ Leaflet spirit (suporta o uso comum no núcleo, delega outros casos de uso para plug-ins).
Você pode resolver o problema facilmente em primeiro lugar especificando os caminhos da imagem, normalmente usando require(image) conforme mostrado em vários comentários acima.

Portanto, embora eu tenha sido o autor desse PR, pessoalmente me sinto desconfortável fundindo-o no núcleo. As mudanças _não são necessárias para a maioria_.

Eles com certeza são bons para tornar a vida dos desenvolvedores mais fácil, mas o problema é causado principalmente pela interação de mecanismos de construção / wrappers de estrutura, cada um tendo suas especificidades, e cada um tendo uma maneira fácil de dizer ao Leaflet onde as imagens estão agora, usando o já existente API.

Talvez devêssemos resolver esse problema com uma documentação melhor (por exemplo, uma seção dedicada ao uso com mecanismos / estruturas de construção?) E / ou um plugin?

Bem, eu não tenho certeza se entendi as complexidades. Mas com certeza seria bom para todos os tipos de desenvolvedores se _todos_ os caminhos das imagens pudessem ser especificados em CSS. Não são apenas usuários do webpack, também são pessoas como eu usando o pipeline de ativos Rails ou Django que anexa um hash a cada ativo estático ...

Eu experimentei exatamente o mesmo problema:
dados: imagem / png; base64, iVBORw0 ... AAAAASUVORK5CYII = ") marker-shadow.png net :: ERR_INVALID_URL

A solução é substituir:

getIconUrl: function (name) {
        if (!IconDefault.imagePath) {   // Deprecated, backwards-compatibility only
            IconDefault.imagePath = this._detectIconPath();
        }

        // <strong i="8">@option</strong> 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.
        return (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);
    },

com:

 // ...
  const url = (this.options.imagePath || L.Icon.Default.imagePath);

  return url.slice(0, -2);

como sugerido por codeofsumit.

Achei muito chato e esse fato de haver um PR para consertá-lo, mas não mesclado por causa da "sensação" de que "As mudanças não são necessárias para a maioria." Desculpe, mas tenho visto pessoas lutando com isso em PHP, RoR, Python (Django) e node.js, então onde você acha que está "a maioria" além desses grupos? Qual estrutura compatível você recomendaria?

Eu concordo com @macwis

Tendo o mesmo problema e este tópico é muito longo. Por que não mesclar o PR?

Isso não é um sentimento, é um fato: a maioria não usa framework, ou aqueles que não mexem com CSS.
A última vez que verifiquei, o Leaflet não foi baixado do CDN descompactado, ou seja, CSS descompactado e descompactado.

A solução adequada é definir as opções de ícone padrão, conforme explicado em muitas mensagens acima.
Muitos frameworks fazem isso como parte de seu plugin de integração de folheto.

Se quiser uma solução mais automática, você ainda tem a opção de publicar um plugin.

Por que não mesclar o PR?

Leia os comentários, por exemplo, https://github.com/Leaflet/Leaflet/issues/4968#issuecomment -382639119

Eu gostaria apenas de dar uma pequena dica: você também pode usar o CDN ao usar um framework. Isso é o que fazemos, por exemplo, com nosso aplicativo React. Carregamos grandes bibliotecas via CDN.

@ googol7 obrigado por sua contribuição.

Por favor, corrija-me se eu estiver errado: se você carregar o folheto através do CDN, muito provavelmente significa que você não alterou seu CSS. Portanto, seus usuários são a maioria.

@ghybs : O que eu tive que fazer foi o seguinte:

// Workaround: https://github.com/Leaflet/Leaflet/issues/4968#issuecomment-269750768
/* eslint-disable no-underscore-dangle, global-require */
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"),
})
/* eslint-enable no-underscore-dangle, global-require */

nossa configuração do webpack se parece com isto:

module.exports = {
    externals: {
        leaflet: "L",
    },
}

@ googol7 obrigado pelos detalhes de sua configuração.

Então você quer dizer que carrega o Leaflet JS do CDN, mas agrupa o CSS e as imagens em seu aplicativo.

@ghybs sim, acho que é o que está acontecendo aqui.

Certifique-se de seguir as duas primeiras etapas: https://leafletjs.com/examples/quick-start/
Tive um problema semelhante porque estava usando o css do tutorial de outra pessoa, mas este deve ser usado

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin=""/>

e então o roteiro do folheto imediatamente depois disso

<script src="https://unpkg.com/[email protected]/dist/leaflet.js" integrity="sha512-/Nsx9X4HebavoBvEBuyp3I7od5tA0UzAxs+j83KgC8PU0kgB4XiK4Lfe4y4cgBtaRJQEIFCW+oC506aPT2L1zw==" crossorigin=""></script>

Olá a todos,

Publiquei o plug - in do leaflet-defaulticon-compatibility " que obtém o código do meu PR https://github.com/Leaflet/Leaflet/pull/5771.
Ao usar esse plugin, o ícone padrão do folheto não tenta mais reconstruir os caminhos da imagem do ícone, mas depende totalmente do CSS. Dessa forma, ele se torna totalmente compatível com mecanismos de construção e estruturas que gerenciam automaticamente ativos com base em CSS (e geralmente reescrevem url() 's).

Basta carregar o plugin (CSS + JS) _after_ Leaflet.
Por exemplo, no webpack:

import 'leaflet/dist/leaflet.css'
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css'
import * as L from 'leaflet'
import 'leaflet-defaulticon-compatibility'

( demonstração )

Embora eu possa entender que muitos desenvolvedores teriam preferido que esse recurso fosse incorporado diretamente no núcleo do Leaflet, foi argumentado que o código adicionado é inútil para a maioria dos usuários finais. Portanto, alinhado com o espírito do Leaflet de manter seu núcleo simples, decidi torná-lo um plugin.

Sinta-se à vontade para abrir um problema no repositório do in, caso tenha problemas ou dúvidas sobre como ele funciona.

O fato é que, se você estiver usando o webpack, você terá esse problema. Vejo a tendência de cada vez mais sites usando webpack. Colocar isso como um plug-in é menos do que ideal, IMHO, pois não vejo pessoas procurando um plug-in para corrigir esse tipo de problema (muito parecido com o que fiz quando abri um dup).
Eu gostaria muito de ver este folheto interno, pois isso é mais uma correção de bug do que um recurso ...

Se você quiser resolver esse problema no Angular 6, basta escrever angular.json :

 {
         "glob": "**/*",
         "input": "./node_modules/leaflet/dist/images/",
         "output": "./assets/leaflet/"
  }

Depois disso, substitua o comportamento padrão de Marker , como algumas das respostas anteriores sugerem:

import { Icon, icon, Marker, marker } from 'leaflet';

@Component({
   selector: 'app-something',
   templateUrl: './events.component.html',
   styleUrls: ['./events.component.scss']
})
export class SomeComponent implements OnInit {
  // Override default Icons
  private defaultIcon: Icon = icon({
    iconUrl: 'assets/leaflet/marker-icon.png',
    shadowUrl: 'assets/leaflet/marker-shadow.png'
  });

  ngOnInit() {
     Marker.prototype.options.icon = this.defaultIcon;
  }
}

O pacote Angular que usei e teve o mesmo problema que aqui é: ngx-leaflet

NOTA:
Há um pequeno problema no Angular 6, como a resposta de _t.animal_ no StackOverflow diz

Esteja ciente de que no Angular 6 existem dois construtores build e test .

Certifique-se de colocá-lo em build .

@ marko-jovanovic obrigado pela informação, mas e se eu não estiver usando esses recursos e quiser reduzir o tamanho do meu pacote?
Sua sugestão ainda se enquadra na minha definição de solução alternativa, IMO.

@HarelM Bom não pude vir com outra solução porque estava com pressa para terminar o projeto escolar. Não é perfeito e sei que aumenta o tamanho do pacote, mas minha solução foi suficiente para mim e esperava que minha resposta pudesse ajudar outras pessoas de alguma forma.

@marko-jovanovic, sua solução é ótima e também espero que possa ajudar outras pessoas. Estou apenas esperando uma solução, não uma solução alternativa :-)

@ marko-jovanovic Oi, também estou participando de um projeto escolar (Angular 6) e não consigo descobrir por que as coisas não funcionam para mim. Para ser honesto, sou um novato total em todas essas coisas aqui.

Quando eu insiro seu código na função ngOnInit do meu componente, ele lança um erro na parte onde você definiu iconUrl e shadowUrl :

Argument of type '{ iconUrl: (options: IconOptions) => Icon<IconOptions>; shadowUrl: any; }' is not assignable to parameter of type 'IconOptions'. Types of property 'iconUrl' are incompatible. Type '(options: IconOptions) => Icon<IconOptions>' is not assignable to type 'string'.

Estou esquecendo de algo? Desde já, obrigado!

@gittiker Eu atualizei uma resposta com o exemplo de importações, componente e ngOnInit. Deixe-me saber se tudo correu bem. :)

@gittiker Eu atualizei uma resposta com o exemplo de importações, componente e ngOnInit. Deixe-me saber se tudo correu bem. :)

Sim, muito obrigado, finalmente funciona. Tive que manipular um pouco o seu URL para que seja
'assets/leaflet/images/marker-icon.png vez de 'assets/leaflet/marker-icon.png', . O mesmo vale para a imagem sombreada.

@ crob611 Muito obrigado, tentei resolver o problema com este método.

@marko-jovanovic você me salvou! mas como @HarelM diz, não tem solução?

muito obrigado, mas para mim serviu o seguinte código: (Angular 6 e folheto 1.3.4)
Primeiro passo
(https://codehandbook.org/use-leaflet-in-angular/)
Mas então o ícone não foi mostrado
erro obter imagem do ícone
net :: ERR_INVALID_URL
resolva-o inserindo o seguinte código no componente
delete L.Icon.Default.prototype._getIconUrl; `

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

Solução usando o folheto 1.3.4 com vue2-folheto 1.2.3:

import { L, LControlAttribution, LMap, LTileLayer, LMarker, LGeoJson, LPopup } from 'vue2-leaflet'
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')
})

Meus 2 centavos: meu problema com o webpack era apenas devido aos nomes dos arquivos em hash, então configurei file-loader para não criar hash nas imagens do folheto:

use: [{
    loader: 'file-loader',
    options:
      {
        name(file) {
          console.log(file)
          if (file.match(/(layers-2x\.png|layers\.png|marker-icon\.png|marker-icon-2x\.png|marker-shadow\.png)/)) {
            return '[name].[ext]'
          }

          return '[name]-[hash].[ext]'
        },
        context: 'app/frontend' // <-- project specific
      }
  }]

AFAIK rude, mas eficiente.

@ghybs obrigado pelo hotfix. Já encontrei esse bug algumas vezes em projetos diferentes. Este tópico inteiro parece absurdo que não foi corrigido ou não é visto como um problema.

google me trouxe aqui porque usar a biblioteca com Webpack estava me dando esse erro.

Alguém sabe por que essas imagens não são inline como svg?

Acho que isso poderia ser facilmente resolvido com postcss e postcss-inline-svg . Os ícones se tornariam svg arquivos embutidos em vez de png externos. Os ícones ficarão mais nítidos à medida que o problema for embora.

Alguém sabe por que essas imagens não são inline como svg?

Suporte a navegador legado.

Obrigado @IvanSanchez

Então vejo duas soluções potenciais. Uma é colocar as imagens em linha como codificado em base64 .png . A outra alternativa é incorporar os ícones .svg e fazer com que os desenvolvedores voltados para plataformas legadas substituam os ícones padrão.

Alguma dessas soluções vale uma solicitação de pull?

De todos os navegadores suportados por leaflet , o seguinte não tem suporte para svg ( caniuse ).

  • IE 7 e 8
  • Navegador Android 2. *

inline as imagens como base64

Consulte https://github.com/Leaflet/Leaflet/issues/4968#issuecomment -322422045

Tive que adicionar âncora e tamanho também para fazer funcionar, por exemplo

   import icon from 'leaflet/dist/images/marker-icon.png';
   import iconShadow from 'leaflet/dist/images/marker-shadow.png';

   let DefaultIcon = L.icon({
      iconUrl: icon,
      shadowUrl: iconShadow,
      iconSize: [24,36],
      iconAnchor: [12,36]
    });

    L.Marker.prototype.options.icon = DefaultIcon; 

Eu também tenho o mesmo problema (webpack usando Flask, então todos os elementos devem estar em uma pasta estática), mas a correção @ giorgi-m não é suficiente, pois recebo um erro de 'exportação é somente leitura' ( Firefox, parece estar ligado às importações de png?).
Vejo que o problema foi resolvido, mas ainda vemos problemas com 1.4.0, então me pergunto qual é a solução?

Vendo este problema com o folheto vue2 2.0.2 e o folheto 1.4.0.

isso parece ter existido por um bom tempo e metade das soluções apresentadas não parecem funcionar.

Alguém descobriu a raiz deste problema?

estou tendo o mesmo problema com as versões "vue2-leaflet": "2.0.3" folheto "folheto": "1.4.0".

também executando o webpack.

Estamos usando com sucesso o vue2-leaflet 2.0.3 e o folheto 1.4.0 usando uma solução encontrada neste mesmo problema:

import L from 'leaflet'
require('../../node_modules/leaflet/dist/leaflet.css')

// FIX leaflet's default icon path problems with webpack
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')
})

Acho que a melhor pergunta a ser feita é por que isso não foi corrigido com o código mesclado que fez com que o problema fosse encerrado. Uma vez que uma solução alternativa que funciona é ótima, mas isso deve funcionar fora da caixa e ainda precisa ser um problema em aberto.

Prezados,

Folheto funciona fora da caixa.

O Webpack (e outros mecanismos de construção) combinado com o Leaflet não funcionam fora da caixa.

Consulte a solução proposta em https://github.com/Leaflet/Leaflet/issues/4968#issuecomment -399857656: leaflet- defaulticon

Embora eu possa entender que muitos desenvolvedores teriam preferido que esse recurso fosse incorporado diretamente no núcleo do Leaflet, foi argumentado que o código adicionado é inútil para a maioria dos usuários finais. Portanto, alinhado com o espírito do Leaflet de manter seu núcleo simples, decidi torná-lo um plugin.

Com o webpack, outra solução típica , depois de configurar seus carregadores:

import L from 'leaflet';
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'),
});

Existem outras soluções propostas mais acima neste segmento para outros motores de construção e combinações de framework.

Para evitar que essas soluções sejam enterradas ainda mais em comentários, vou bloquear este tópico.

Obrigado a todos pelas soluções compartilhadas! : +1:

Esta página foi útil?
0 / 5 - 0 avaliações