Leaflet: L.Icon.Default 带来了错误的图片网址

创建于 2016-09-28  ·  90评论  ·  资料来源: Leaflet/Leaflet

  • [ x] 我正在报告一个错误,而不是寻求帮助
  • [ ] 我查看了文档以确保行为已记录并符合预期
  • [x] 我确定这是 Leaflet 代码问题,不是我自己的代码问题,也不是我使用的框架(Cordova、Ionic、Angular、React……)
  • [ ] 我已经搜索了问题以确保它尚未报告

图像 url 传单 prsents 我是https://uismedia.geo-info-manager.com/apis/leaflet_1/imagesmarker-icon-2x.png。 好像少了一个“/”
另外我有一个错误
Leaflet.min.js:5 GET https://uismedia.geo-info-manager.com/apis/leaflet_1/images/ 403(禁止)

compatibility

最有用的评论

想分享我为解决无效数据所做的工作

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;

可能也可以调整为包括视网膜图标。

所有90条评论

  • 您的服务器中是否有任何公共网页我们可以访问,以便我们自己重现问题?
  • 您使用的是什么操作系统和网络浏览器?

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

这可能来自https://github.com/Leaflet/Leaflet/issues/4849 中讨论的同一问题

的确。 这就是为什么我很想知道可以复制的情况,所以我们可以针对这些情况进行单元测试。

我在从 RC3 移动到 1.0.1 时遇到了同样的问题 - 在我的代码中,我有一行 L.Icon.Default.imagePath = 'images'; - 不太记得为什么会这样,但是评论它解决了这个问题 - 可能值得检查一下你没有类似的

突然在两个完全不同的项目中遇到了同样的问题,都使用 webpack 和传单。
如果我向地图添加标记,则找不到图像。 浏览器抛出这个错误:
image

好的,我得到了一些东西。

所以标记目前看起来像这样,因为没有找到图像(图标和阴影)。
image

传单中的此功能:

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

导致data:image网址在网址末尾具有以下字符串:
")marker-icon-2x.png

如果删除+ L.Icon.prototype._getIconUrl.call(this, name)则可以删除文件名。 ")部分可能来自_detectIconPath正则表达式魔术。 我无法解决这个问题,所以我只是尝试将最后两个字符切掉,结果是这个函数:

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

我们开始了,图标出现了。 最后一个问题是阴影图像也是一个标记图标 - src 路径已经错误,我不知道为什么(还)。 所以标记现在看起来像这样:

image

@IvanSanchez这是否有助于您缩小问题的范围?

@codeofsumit会很高兴通过_detectIconPath并查看那里发生了什么,尤其是path变量在通过正则表达式之前具有什么值。

@IvanSanchez @perliedman我想我发现了这个错误。

这是_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[\"\']?\)$/, '') : '';
}

path变量是这样的:
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQ…n3EUrUZ10EYNw7BWm9x1GiPssi3GgiGRDKWRYZfXlON+dfNbM+GgIwYdwAAAAASUVORK5CYII=")

哪个是对的。

现在正则表达式想要从中提取 data.image url,它返回这个:

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

请注意未从path变量中删除的最后一个") 。 正则表达式/^url\([\"\']?/仅针对路径开头的url(" ,而不是结尾的")
使用此正则表达式有效:

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

这解决了图像问题,以及

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

里面_getIconUrl 。 但它并不能修复阴影——我仍然不知道阴影是怎么回事。

有同样的问题,
_detectIconPath 中的路径值类似于 "url("data:image/png;base64,i...5CYII=")"
看起来 _getIconUrl 和 _detectIconPath 不是为了处理数据 URL

阴影问题似乎被事实是原因_getIconUrl的价值L.Icon.Default.imagePath已设置与标记数据URL,因此用于标记的图像和拉伸
image

它可能与此提交硬编码标记图像有关吗?
https://github.com/Leaflet/Leaflet/commit/837d19093307eb5eeb1fca6536962a1ab1573dd5

@Radu-Filip 我能够通过对您的 PR 进行这些修改来修复它 - 但我不确定这可能会产生什么其他影响:
image

问题是 - 正如你所说 - 默认 URL 是标记图像,基本上所有图标。
所以首先我将阴影的默认 URL 添加到 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);
}

然后我将名称从_getIconUrl传递给_detectIconPath并使用它将类添加到从中提取路径的元素中:

_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)?[\"\']?\)$/, '') : '';
}

我还必须删除detectIconPath周围的 if/else ,因为它不是为阴影图标调用的。 现在一切都适用于默认标记图标 - 不确定自定义标记图标。

@codeofsumit是的,我在这里做了类似的事情https://github.com/Radu-Filip/Leaflet/tree/temp
现在我将使用 if 作为一个 hack。 希望对于那些使用 webpack 等人的人来说,未来会有更多的解决方案

@Radu-Filip 你介意用那个解决方案更新你的 PR 吗? 它可能会合并。

@codeofsumit做完了,看看能不能通过

你好,

也许我错过了一些东西,但在我看来,这个 Webpack 构建问题可以简单地通过 Leaflet 插件解决,这将覆盖L.Icon.Default行为。

演示: http :

使用这种方法,您可以摆脱任何棘手的 RegExp,并且默认标记图像被内联(通过硬编码),无论如何,这是 Webpack 对小图像的预期结果之一。

一个可能的缺点是每个标记都有自己的 base64 图标,不确定浏览器是否可以缓存......(PR #5041 的缺点相同)
我们可以想象通过将其设置为背景图像而不是将其放置在图像src属性中来进行改进,例如对图层控制图标所做的那样。
这个想法可能有一个隐藏的陷阱(编辑:听起来像那个),否则我相信它会在很久以前实现,因为它首先会避免图像路径检测。

演示: http :

插件方法的最大优点是它只为 Webpack 项目保留了这种特定行为。

希望这可以帮助。

顺便说一句,在我看来,这里有一些本质上的错误。

Leaflet 对图像进行“复杂”路径检测,与 CSS 文件相比,它必须位于预定义的位置。

但是 webpack 构建过程捆绑了 CSS,并且可能(或不)移动图像(并重命名它们!),这取决于开发人员对 webpack 的请求(比如需要图像)。
因此,当使用 webpack 时,Leaflet 检测肯定会失败。

PR #5041 就像一个技巧来接受 webpack 将图像内联到 CSS 中的情况,代价是将 Base64 图像复制到每个标记中。 甚至不谈论非 webpack 用户的成本。

PR #4979 只是为了防止 webpack 构建错误消息(由于文件丢失),它看起来根本不处理实际的图像路径分辨率。
我猜开发人员然后手动指定L.Icon.Default.imagePath
@jasongrout@Eschon ,也许你可以分享你是如何管理它的?

我真的不会管。 我只是不使用默认图标,所以直到现在这个错误对我来说都不是问题。

嗨,只是说明我可以使用此库的 1.0.1 版本重现此路径错误。
我将它与传单 Drupal 模块 (7.x-1.x-dev) 一起使用,这里有一个问题报告给模块: https :

据我所知,“问题”出在 _getIconUrl 函数上? 因为在L.Icon.Default.imagePath之后缺少一个斜杠,所以例如 Drupal 中的图像路径会像这样生成“ /sites/all/libraries/leaflet/imagesmarker-icon.png ”。 在图像路径和标记图像文件名 (marker-icon.png) 之间应该是一个斜杠 /。

嗨@anairamzap-mobomo,

听起来你报告的是一个不同的问题。

不幸的是,由于它似乎涉及到框架 (Drupal) 的端口,因此您必须首先确保该错误与该端口的工作方式无关。

带有 vanilla JS 的 Leaflet 1.0.x 正确包含尾部斜杠: http :

参见例如http://cgit.drupalcode.org/leaflet/tree/leaflet.module#n51 ,其中L.Icon.Default.imagePath被 Drupal 模块覆盖。

看起来该模块不处理 Leaflet 0.7.x 和 1.0.x 之间的更改,其中斜杠现在必须包含在L.Icon.Default.imagePath

由于 Leaflet 1.0.0 是一个主要版本,我想没有向后兼容性的承诺。

@ghybs我明白了...我会联系 Drupal 模块维护者让他们知道这一点。 正如您所说,听起来他们必须修改模块以适应库的 1.0.x 版本,或者至少在有关此的文档警告中添加一些行。

感谢您的反馈意见!

我遇到了与最初报告的完全相同的问题——在 aurulia skeleton/esnext+webpack 项目中。

在解决此问题之前,我已将图像复制到我的源文件夹中并使用自定义标记——省略大小/位置信息似乎没问题......

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

想分享我为解决无效数据所做的工作

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;

可能也可以调整为包括视网膜图标。

任何人都可以发送修改后的 Leaflet.js 文件吗?
@ajoslin103使用的代码:
```var customDefault = L.icon({
iconUrl: 'images/marker-icon.png',
shadowUrl: 'images/marker-shadow.png',
});

我没有修改 Leaflet.js 文件,我只是将标记图像从传单分发中复制到我的普通图像文件夹中,然后使用我发布的那个片段作为自定义图标。

我无法使用 crob611 的解决方案,因为它们在原始 css 中被引用为 http,而我的网站是通过 https 提供的。

``` 函数 onLocationFound(e) {
var 半径 = e.accuracy / 2;
var customDefault = L.icon({
iconUrl: 'marker_icon_2x',
shadowUrl: 'marker_shadow.png'
});
L.marker(e.latlng).addTo(map)
.bindPopup("你在距离这个点 " + 半径 + " 米内").openPopup();
L.circle(e.latlng, radius).addTo(map);
}

如何设置新图标?

我在构造函数中创建了自定义图标(我使用的是 Aurelia 框架)

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

然后当我在 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);

参考: http :

在解决这个问题之前,我是否建议在_getIconUrl() (或其他)意外遇到数据 UI 时添加运行时警告,通过console.warn或其他方式指向 Github 问题 URL像那样。

这将带给人们同样的问题到合适的位置,并提出解决方法(像这样一个为我工作)。

这就是 React(开发构建)帮助开发人员识别问题的方式。

从反应问题,@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'),
});

这可以在不更改传单核心文件的情况下解决问题。

@codeofsumit :仅供参考,据我所知,此解决方法仅适用于提到的三个图标。

如果 Leflet 确实(或将来会)以类似方式需要其他图标(可能适用于其他组件 - 我不知道),则需要调整解决方法。


对于那些不熟悉 Webpack 的人:Webpack 将为这些属性分配新的 URL:

/***/ 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)
    });

(细节很大程度上取决于所使用的 Webpack 配置)

@jampy当然是的。 因此,这是一种解决方法。 但是,无论如何,对传单核心的任何修改都会在每次更新时被删除。 我将使用提到的解决方法,直到有一个适当的修复,因为它看起来最不痛苦。

同样的问题, detectIconPath函数为路径url("http://localhost:8080/2273e3d8ad9264b7daa5bdbf8e6b47f8.png")返回http://localhost:8080/2273e3d8ad9264b7daa5bdbf8e6b47f8.png") url("http://localhost:8080/2273e3d8ad9264b7daa5bdbf8e6b47f8.png")

它远非理想,但我使用 webpack 并使用此解决方法

我将图像复制到项目根目录下的图像文件夹中

然后在我的 package.json 中我添加了一个 postbuild npm 脚本(在脚本部分)
" postbuild:prod ": "./Post-Build4Prod.sh"

将图像文件夹复制到 dist

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

然后我为图标定义了一个 customDefault

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

并在任何地方使用它

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

@ajoslin103 ,考虑这个解决方法。 它更简单,您最终会得到相同的结果。

我在 Vue webpack 项目中使用以下方法解决此问题:

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

我在 Django 的 collectstatic 和 CachedStaticFilesStorage 中遇到了同样的问题,它将文件内容的哈希值添加到静态文件的名称中,因此标记图标.png 变为标记图标.2273e3d8ad92.png,然后是 _detectIconPath 末尾的正则表达式不匹配。

我将其更改为replace(/marker-icon[^"']+\.png[\"\']?\)$/, '')对我有用。

我目前也有这个问题。
使用 Leaflet 1.0.3 和 Angular2。
我承认,鉴于此线程,我不知道如何解决它。

对于 Angular 2 & 4
我用代码创建了一个文件 require.d.ts :

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;

然后使用要求对于这个问题:

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

带有 webpack 的 Vue.js 的解决方法(带有大小和锚点):

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]
})

我做了一些快速的性能测试,将默认图标内联为 base64 与使用外部图像 URL。 当加载 _a lot_ 标记(在我的例子中为 1000)时,base64 内联图像的性能明显更差。

这是加载 1000 个标记图标作为外部 URL 时的 Chrome devtools 性能视图:

1000 markers icons as external URLs

相比之下,使用 1000 个标记图标作为内联 base64(请注意时间线的不同比例,抱歉):

1000 markers icons as inlined base64 URLs

可以看出,由于某种原因,在使用内联图像时图层组合会延迟,这使得整个加载时间大约需要一秒钟。

对于随意使用,这可能无关紧要,但如果您使用大量标记,这可能是相关的。

关于如何处理这个长期问题的建议:

  • 修复 #5041 以解决代码审查中提到的问题; 这将使内联图标开箱即用
  • 如果使用内联图标,则记录警告,以表明这可能不理想

另一种选择是恢复到旧的 (0.7) 方法来检测图像路径,但我们知道还有其他我们无法解决的问题。

@perliedman

不错的剖析!
它回答的疑惑我关于下重新使用内嵌图片的一侧。

事实上,PR #5041 可以被重构,这样当图标图像被内联到 CSS 中时,Leaflet 可以立即工作(通过像 webpack 这样的构建引擎)。
我能想到的解决方案(大部分类似于提到的 PR)意味着每个图像创建 1 个类,因此它会将 CSS(可能还有 JS)文件大小增加几十个字节。

示例: http :

但就像我之前提到的,不幸的是,出于兼容性原因(与构建引擎)的这种更改会影响不使用这些框架和构建过程的用户。

另一方面,结果可能更“干净”,因为我们可以去掉IconDefault类选项中的硬编码文件名,并将完整路径(包括文件名)委托给 CSS。
这非常有趣,因为(如果我理解正确的话)这个复杂检测的重点是将图像位置与 JS 文件分离,并依赖它们与 CSS 文件的相对位置。 因此对我来说,即使文件名也是在 CSS 中定义的。

但是,试图保持与imagePath选项的兼容性也可能很复杂,因为它可能需要重新处理之前检测到的图像路径,以替换前导路径并保留文件名。 因此,我们将在那里引入一个新的 RegExp。

最后,我不确定这是否会涵盖所有情况。
构建过程可以高度定制,导致图标图像等静态资产的情况非常不同。 可能仍然存在一些极端情况,即使上述方法也会失败。

@ghybs我喜欢那个例子(http://playground-leaflet.rhcloud.com/dulox/)!

也许做的太过分了,但是你怎么看待在这个 CSS 中指定图标 _size_ (使用widthheight )? 我可以想象有人覆盖这些 CSS 规则来更改默认图标,却发现它现在具有错误的尺寸。

不管有没有 CSS 中的尺寸,我认为这是一个很好的前进方向。 你愿意按照你的例子做一个 PR 吗? 如果你现在没有时间或精力,我可以继续做,告诉我你喜欢什么。

我很想结束这个问题,因为实际上我自己也偶然发现了这个问题。

@perliedman

我同意能够通过 CSS 指定图标大小会更好。

但在那种情况下,为了一致性,我们也应该能够指定锚点。 我不确定哪个 CSS 规则适合于此(可能是边距?)。 如果这是可能的,那么我认为结果会非常好:图标将完全在 CSS 中定义。

更进一步,这可能是定义图标的一种额外方式:指定 3 个 CSS 类(图标、视网膜、阴影),Leaflet 将从它们中提取所有图标选项。

请随意处理这个问题,不幸的是,我不确定什么时候我能得到一些时间......

在前面的示例的基础上,这里有一个概念,即阅读paddingmargin CSS 规则以确定iconAnchor ( shadowAnchor ) 和popupAnchor选项:
http://playground-leaflet.rhcloud.com/xuvi/1/edit?html ,css,output

我不喜欢我使用padding来确定iconAnchor的事实,因为最终 Leaflet 使用margin来定位图标图像......
但与我们指定图标选项的方式相比,我发现在 CSS 中快速指定内容是最容易的,并且避免恢复值。

虽然我喜欢在 CSS 中指定所有内容的结果,但仍然需要做更多的工作来保持与L.Icon.Default.imagePath向后兼容性。

我很抱歉我没有时间创建 PR。

我刚刚诊断出另一种_detectIconPath失败的情况:使用 Firefox 时(使用 ESR 和当前版本测试)并设置首选项 → 内容 → 颜色... → 使用上面的选择覆盖页面指定的颜色:始终Firefox 将删除background-image属性包括.leaflet-default-icon-path background-image属性,从而破坏_detectIconPath

我不知道有多少人在使用 Firefox 的这个功能,但我已经使用它很长时间了。

url()可以用作其他 CSS 属性的值吗? 就像使用以下 CSS: .leaflet-default-icon-path { -leaflet-icon: url(images/marker-icon.png); }或者自己定义和使用自定义 CSS 属性是不可能的? 没有浏览器需要_理解_ -leaflet-icon属性,但是他们仍然需要填充它并使其值可用于脚本。

@roques

感谢您在 Firefox 中使用此特定选项时报告此问题!
看起来 Chrome 有一个高对比度扩展,但它只会改变颜色,而不会破坏 Leaflet 中的任何内容。

不幸的是,Firefox 确实删除了它不理解的 CSS 属性。
然而,图像 CSS 数据类型可以与其他一些规则一起使用,包括cursor ,即使在 Firefox 中使用颜色覆盖设置,它看起来也能正常工作:
http://playground-leaflet.rhcloud.com/yov/1/edit?html ,css,output

我发现使用cursor而不是background-image不太优雅,因为它的用法与我们通过 CSS 样式制作标记的方式相去甚远……但无论如何这已经是对路径的一种黑客攻击仅检测。

我正准备做一个 PR 来解决 webpack 问题,我现在将包含这个解决方法。
我不知道我们如何为这种情况进行自动化测试,但我认为解决方法应该已经很好了。

有人为这个问题找到了明确的解决方案吗?

基于@Shiva127的回答,对于使用 Angular + Angular CLI 的任何人:

你可以把它放在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;

并在您的.angular-cli.json添加 glob 行:

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

这将在构建时将图标复制到 dist 文件夹中的 assets 文件夹中(您不会在 src/assets 中看到它们)。 此外,将工作放在app.module.ts是保持全局原型修改导入(例如 RxJS 可观察补丁)的好地方。 这样,在代码库中的其他位置导入 Marker 将正常运行。

我已经解决了这个问题。

我提供了一个默认图标来标记 drawOptions:

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

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

...

然后在 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/";
       }
 });


最后在显示图层时我设置了 imagePath:

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

@codeofsumit这些修复是否包含在最新版本 1.3.1 中? 令人惊讶的是,我使用的是 1.3.1 版,但仍然面临同样的问题。

@vishalrajole 据我所知,提交来解决这个问题的唯一 PR 是 #5041,它已经开放并请求更改了 _long_ 时间。

我们还有替代解决方案#5771,它很好但涉及更多更改。

所以,总结一下:没有人提交过接受的 PR 来解决这个问题,欢迎帮助!

@perliedman从外观

@mb21

#5771 涉及的更改是必要的

实际上,提议的更改有两种类型:

  • 读取每个图像路径而不仅仅是图像文件夹位置,以便由构建引擎(如 webpack 文件加载器)修改的 url 按原样读取,而不是重建/猜测。
  • 从 CSS 读取所有其他默认图标选项,以便所有配置都集中在一个地方。

如果第一点无法避免,第二点很有趣,即使它添加了相当多的代码。

第一个实际上是对使用在 CSS 中摆弄 url 的构建引擎的开发人员的青睐。 即使在开发人员花费相当多的时间调整他们的配置的新环境中,它也能保持 Leaflet _zero config精神_(如果你使用 webpack 文件加载器,无论如何你都需要一个自定义配置),代价是为其他人添加了相当多的代码,这恕我直言 _against_ Leaflet 精神(支持核心中的常见用法,将其他用例委托给插件)。
通过指定图像路径,您可以很容易地首先解决问题,通常使用require(image) ,如上面的许多注释所示。

因此,即使我编写了那个 PR,我个人对将它合并到核心中感到不舒服。 这些变化_对大多数人来说不是必需的_。

他们确实很好地让开发人员的生活更轻松,但问题主要是由构建引擎/框架包装器的交互引起的,每个引擎/框架包装器都有自己的特性,每个都有一个简单的方法来告诉 Leaflet 现在图像在哪里,使用已经存在的应用程序接口。

也许我们应该用更好的文档(例如专门用于构建引擎/框架的部分?)和/或插件来解决这个问题?

好吧,我不确定我是否理解其中的复杂性。 但是,如果 _all_ 图像路径可以在 CSS 中指定,那么对于各种开发人员来说肯定会很好。 不仅是 webpack 用户,还有像我这样使用 Rails 或 Django 资产管道的人,这些管道将哈希附加到每个静态资产...

我遇到了完全相同的问题:
data:image/png;base64,iVBORw0...AAAAAASUVORK5CYII=")marker-shadow.png net::ERR_INVALID_URL

解决方法是更换:

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

和:

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

  return url.slice(0, -2);

正如codeofsumit所建议的那样。

我发现这真的很烦人,事实上有一个 PR 来修复它但没有合并,因为“感觉”“大多数人不需要更改”。 抱歉,我已经看到有人在 PHP、RoR、Python (Django) 和 node.js 中苦苦挣扎,那么您认为这些群体之外的“大多数”在哪里? 你会推荐什么兼容的框架?

我同意@macwis

有同样的问题,这个线程很长。 为什么不合并 PR?

这不是感觉,而是事实:大多数不使用框架,或者不使用 CSS 的框架。
上次我检查时,Leaflet 是从 unpkg CDN 下载的第一个,即未捆绑和未处理的 CSS。

正确的解决方案是定义默认图标选项,如上述许多消息中所述。
许多框架将其作为其 Leaflet 集成插件的一部分。

如果您想要更自动化的解决方案,您仍然可以选择发布插件。

为什么不合并 PR?

阅读评论,例如https://github.com/Leaflet/Leaflet/issues/4968#issuecomment -382639119

我只想提出一点提示:在使用框架时,您也可以使用 CDN。 例如,这就是我们使用 React App 所做的。 我们通过 CDN 加载大库。

@googol7感谢您的投入。

如果我错了,请纠正我:如果您通过 CDN 加载 Leaflet,则很可能意味着您没有更改其 CSS。 因此,您的用户占大多数。

@ghybs :我必须做的是:

// 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 */

我们的 webpack 配置如下所示:

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

@googol7感谢您提供配置的详细信息。

所以你的意思是你从 CDN 加载 Leaflet JS,但在你的应用程序中捆绑 CSS 和图像。

@ghybs是的,我想这就是这里发生的事情。

请务必遵循前两个步骤: https :
我有一个类似的问题,因为我使用的是别人教程的 css,但必须使用这个

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

然后是紧随其后的 Leaflet 脚本

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

大家好,

我发布了 Leaflet 插件“ leaflet-defaulticon-compatibility ”,它从我的 PR https://github.com/Leaflet/Leaflet/pull/5771获取代码
通过使用该插件,Leaflet 默认图标不再尝试重新构建图标图像路径,而是完全依赖于 CSS。 这样,它就与基于 CSS 自动管理资产的构建引擎和框架完全兼容(并且通常重写url() )。

只需加载插件(CSS + JS)_after_ Leaflet。
例如在 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'

演示

虽然我可以理解许多开发人员更愿意将此类功能直接合并到 Leaflet 核心中,但有人认为添加的代码对大多数最终用户无用。 因此,本着保持其核心简单的 Leaflet 精神,我决定将其作为插件。

如果您对插件库的工作方式有任何疑问或疑虑,请随时在

事实是,如果您使用 webpack,则会遇到此问题。 我看到越来越多的网站使用 webpack 的趋势。 将它作为插件放置并不理想,恕我直言,因为我没有看到人们在寻找插件来解决此类问题(就像我打开 dup 时所做的那样)。
我非常希望看到这个内部传单,因为这更像是一个错误修复而不是一个功能......

如果您想在 Angular 6 中解决此问题,只需写入angular.json

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

之后,覆盖Marker默认行为,正如之前的一些答案所暗示的那样:

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;
  }
}

我使用的 Angular 包和这里有同样的问题: ngx-leaflet

笔记:
Angular 6 中有一个小问题,正如 StackOverflow 上 _t.animal_ 的回答所说

请注意,在 Angular 6 中,建筑师buildtest两个相关的构建器。

确保你把它放在build

@marko-jovanovic 感谢您提供信息,但如果我不使用这些资产并想减小我的包裹大小怎么办?
您的建议仍然属于我对解决方法的定义,IMO。

@HarelM好吧,我无法提出任何其他解决方案,因为我急于完成学校项目。 它并不完美,我知道它会增加包的大小,但我的解决方案对我来说已经足够了,希望我的回答也能以某种方式帮助其他人。

@marko-jovanovic 您的解决方案很棒,我也希望它可以帮助其他人。 我只是希望找到解决方案,而不是解决方法:-)

@marko-jovanovic 嗨,我太忙于学校项目(Angular 6)并且无法弄清楚为什么东西对我不起作用。 老实说,我对这里的所有这些东西完全是个菜鸟。

当我将您的代码插入到我的组件的ngOnInit -Function 中时,它会在您设置iconUrlshadowUrl的部分引发错误:

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'.

我错过了什么吗? 提前致谢!

@gittiker我已经用导入、组件和 ngOnInit 示例更新了一个答案。 如果一切顺利,请告诉我。 :)

@gittiker我已经用导入、组件和 ngOnInit 示例更新了一个答案。 如果一切顺利,请告诉我。 :)

是的,非常感谢,它终于奏效了。 我不得不稍微操作一下你的 URL,所以它是
'assets/leaflet/images/marker-icon.png而不是'assets/leaflet/marker-icon.png', 。 阴影图像也是如此。

@crob611非常感谢,我尝试用这种方法解决问题。

@marko-jovanovic 你救了我! 但是@HarelM怎么说,难道没有解决方案吗?

非常感谢,但对我来说,它提供了以下代码:(Angular 6 和 Leaflet1.3.4)
第一步
(https://codehandbook.org/use-leaflet-in-angular/)
但是后来没有显示图标
错误获取图标图像
net::ERR_INVALID_URL
通过在组件中插入以下代码来解决它
删除 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',
});`

使用传单 1.3.4 和 vue2-leaflet 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')
})

我的 2 美分:我的 webpack 问题只是由于散列的文件名,所以我配置了file-loader以便不散列传单的图像:

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。

@ghybs感谢您的修补程序。 我在不同的项目中遇到过几次这个错误。 整个线程似乎很荒谬,因为它没有修复或不被视为问题。

谷歌把我带到这里是因为使用带有 Webpack 的库给了我这个错误。

有谁知道为什么这些图像不内联为 svg?

我认为这可以通过postcsspostcss-inline-svg轻松解决。 图标将成为内联svg文件而不是外部png 。 随着这个问题的消失,图标会更清晰。

有谁知道为什么这些图像不内联为 svg?

旧版浏览器支持。

谢谢@IvanSanchez

然后我看到了两个潜在的解决方案。 一种是将图像内联为 base64 编码的.png 。 另一种选择是内联.svg图标,并使针对旧平台的开发人员覆盖默认图标。

这些解决方案中的任何一个值得拉取请求吗?

出所有支持的浏览器的小册子,下面没有对SVG(支持caniuse )。

  • IE 7 和 8
  • 安卓浏览器 2.*

将图像内联为 base64

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

也必须添加锚点和大小才能使其工作,例如

   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; 

我也有同样的问题(使用 Flask 的 webpack,所以所有元素都应该在一个静态文件夹中),但是 @giorgi-m 修复是不够的,因为我得到一个“exports”是只读的错误( Firefox,似乎与 png 导入相关联?)。
我看到问题已经解决了,但我们仍然看到 1.4.0 的问题,所以我想知道修复是什么?

在 vue2-leaflet 2.0.2 和 Leaflet 1.4.0 中看到了这个问题。

这似乎已经存在了很长一段时间,并且提出的解决方案中有一半似乎不起作用。

有没有人想出这个问题的根源?

我对版本“vue2-leaflet”:“2.0.3”传单“leaflet”:“1.4.0”有同样的问题。

还运行 webpack。

我们使用在同一问题中找到的解决方案成功地使用了 vue2-leaflet 2.0.3 和 Leaflet 1.4.0:

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

我想需要问的更好的问题是为什么这没有用导致问题被关闭的合并代码来解决? 由于有效的解决方法很好,但这应该是开箱即用的,并且仍然需要成为一个悬而未决的问题。

亲爱的大家,

传单开箱即用。

Webpack(和其他构建引擎)与 Leaflet 结合不能开箱即用。

请参考https://github.com/Leaflet/Leaflet/issues/4968#issuecomment -399857656 中提出的解决方案: leaflet-defaulticon-compatibility

虽然我可以理解许多开发人员更愿意将此类功能直接合并到 Leaflet 核心中,但有人认为添加的代码对大多数最终用户无用。 因此,本着保持其核心简单的 Leaflet 精神,我决定将其作为插件。

使用 webpack,另一个典型的解决方案,一旦你配置了你的加载器:

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

对于其他构建引擎和框架组合,该线程中还提出了其他更高级别的解决方案。

为了防止这些解决方案进一步被评论所掩盖,我将锁定此线程。

感谢大家分享的解决方案! :+1:

此页面是否有帮助?
0 / 5 - 0 等级