Leaflet: L.Icon.Default возвращает неверный URL-адрес изображения

Созданный на 28 сент. 2016  ·  90Комментарии  ·  Источник: Leaflet/Leaflet

  • [x] Я сообщаю об ошибке, а не прошу помощи
  • [] Я просмотрел документацию, чтобы убедиться, что поведение задокументировано и ожидается
  • [x] Я уверен, что это проблема кода Leaflet, а не проблема моего собственного кода или используемой мной инфраструктуры (Cordova, Ionic, Angular, React…)
  • [] Я просмотрел проблемы, чтобы убедиться, что о них еще не сообщалось.

Листовка с URL-адресом изображения, которую мне представляет: https://uismedia.geo-info-manager.com/apis/leaflet_1/imagesmarker-icon-2x.png. Кажется, отсутствует "/"
К тому же у меня ошибка
leaflet.min.js: 5 ПОЛУЧИТЬ https://uismedia.geo-info-manager.com/apis/leaflet_1/images/ 403 (Запрещено)

compatibility

Самый полезный комментарий

Хотел поделиться, что я сделал, чтобы обойти проблему с недопустимыми данными: URL . В основном установите значок по умолчанию на новый, который использует предоставленный значок маркера и тень, но позволит webpack обрабатывать кодирование данных этих изображений индивидуально. Просто включите где-нибудь такой файл.

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 ПОЛУЧИТЬ 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'; - не могу вспомнить, почему это было, но комментирование решило проблему - возможно, стоит проверить, что у вас нет аналогичных

внезапно возникла такая же проблема в двух совершенно разных проектах, как с использованием веб-пакета, так и с помощью листовки.
Если я добавлю маркеры на карту, изображения не будут найдены. Браузер выдает эту ошибку:
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);
},

приводит к тому, что URL-адреса data:image содержат следующую строку в конце URL-адреса:
")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=") .

Что правильно.

Теперь регулярное выражение хочет извлечь из этого URL-адрес data.image и возвращает это:

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

Мне также пришлось удалить if / else около detectIconPath , потому что он не вызывается для значка тени. Теперь все работает для значка маркера по умолчанию - насчет пользовательских не уверен.

@codeofsumit да, я сделал нечто подобное здесь https://github.com/Radu-Filip/Leaflet/tree/temp
а пока я использую if в качестве хака. Надеюсь, что в будущем появится более перспективное решение для тех, кто использует webpack и др.

@ Radu-Filip, вы не против обновить свой PR этим решением? Это может быть объединено.

@codeofsumit готово, давайте посмотрим, пройдет ли он

Привет,

Возможно, я что-то упускаю, но мне кажется, что эту проблему построения Webpack можно просто решить с помощью плагина Leaflet, который переопределит поведение L.Icon.Default .

Демо: http://playground-leaflet.rhcloud.com/nexo/1/edit?html , css, вывод

При таком подходе вы избавляетесь от любого сложного RegExp, а изображения маркеров по умолчанию встроены (путем жесткого кодирования), что в любом случае является одним из результатов, предназначенных для Webpack для небольших изображений.

Возможным недостатком является то, что каждый маркер имеет свой собственный значок base64, не уверен, могут ли браузеры кэшировать его… (тот же недостаток для PR # 5041)
Мы могли бы представить себе усовершенствование, установив его в качестве фонового изображения вместо того, чтобы помещать его в атрибут image src , как, например, для значка Layers Control.
Там могут быть скрытые ловушки с этой идеей (редактирование: звучит как один на

Демо: http://playground-leaflet.rhcloud.com/mey/1/edit?html , css, вывод (не заботясь о сетчатке)

Самым большим преимуществом подхода с использованием плагинов является то, что он сохраняет это специфическое поведение только для проектов Webpack.

Надеюсь это поможет.

Кстати, мне кажется, что здесь что-то не так.

Leaflet выполняет «сложное» определение пути к изображениям, которые должны находиться в заранее определенном месте по сравнению с файлом CSS.

Но процесс сборки webpack связывает CSS и может (или нет) перемещать изображения (и переименовывать их!), В зависимости от того, что разработчик запрашивает у webpack (например, требует изображений).
Следовательно, обнаружение Leaflet обязательно не срабатывает при использовании webpack.

PR # 5041 похож на уловку, позволяющую принять случай, когда webpack встраивает изображения в CSS за счет дублирования изображения Base64 в каждый маркер. Даже не говоря о стоимости для пользователей, не использующих webpack.

PR # 4979 был предназначен только для предотвращения сообщения об ошибке сборки веб-пакета (из-за отсутствия файла), он вообще не пытается обрабатывать фактическое разрешение пути к изображению.
Я предполагаю, что разработчики вручную укажут L.Icon.Default.imagePath ?
@jasongrout и @Eschon , может,

Я действительно не справляюсь. Я просто не использую значок по умолчанию, поэтому до сих пор эта ошибка не была для меня проблемой.

Привет, просто хочу сказать, что я могу воспроизвести эту ошибку пути, используя версию 1.0.1 этой библиотеки.
Я использую его вместе с модулем листовки Drupal (7.x-1.x-dev), и здесь в модуле сообщается о проблеме: https://www.drupal.org/node/2814039 в случае, если его полезный.

Насколько я понимаю, "проблема" связана с функцией _getIconUrl? поскольку после L.Icon.Default.imagePath отсутствует косая черта, путь к изображению, например, в Drupal создается следующим образом: "/ sites / all / libraries / leaflet / imagesmarker-icon.png ". Между путем к изображениям и именем файла изображения маркера (marker-icon.png) должна стоять косая черта /.

Привет @ anairamzap-mobomo,

Похоже, то, о чем вы сообщаете, - это другая проблема.

К сожалению, поскольку это, похоже, связано с переносом на фреймворк (Drupal), вам нужно сначала убедиться, что ошибка не связана с тем, как этот порт работает.

Leaflet 1.0.x с vanilla JS правильно включает в себя завершающую косую черту: http://playground-leaflet.rhcloud.com/fosa/1/edit?html , вывод

См., Например, 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, понятно ... Я

Спасибо за ваш отзыв!

У меня та же проблема, о которой сообщалось изначально - в проекте aurulia skeleton / esnext + webpack.

Пока это не будет исправлено, я скопировал изображения в исходную папку и использую настраиваемый маркер - пропуск информации о размере / размещении кажется нормальным ...

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

Хотел поделиться, что я сделал, чтобы обойти проблему с недопустимыми данными: URL . В основном установите значок по умолчанию на новый, который использует предоставленный значок маркера и тень, но позволит webpack обрабатывать кодирование данных этих изображений индивидуально. Просто включите где-нибудь такой файл.

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 radius = e.accuracy / 2;
var customDefault = L.icon ({
iconUrl: 'marker_icon_2x',
shadowUrl: 'marker_shadow.png'
});
L.marker (e.latlng) .addTo (карта)
.bindPopup ("Вы находитесь в пределах" + радиуса + "метров от этой точки"). openPopup ();
L.circle (e.latlng, radius) .addTo (карта);
}

как мне установить новый значок?

Я создаю пользовательский значок в своем конструкторе (я использую фреймворк Aurelia)

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

Затем я использую его, когда добавляю маркер в метод connected ()

        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://leafletjs.com/examples/custom-icons/

Пока не будет хорошего решения этой проблемы, могу ли я предложить добавить предупреждение во время выполнения, когда _getIconUrl() (или что-то еще) неожиданно встречает пользовательский интерфейс данных, указывающий на URL-адрес проблемы Github через console.warn или что-то еще как это.

Это приведет людей с той же проблемой в нужное место и предложит обходные пути (например, тот, который сработал для меня).

Таким образом 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 : К вашему сведению,

Обходной путь нужно будет скорректировать на тот случай, если Лефлету потребуются (или потребуются в будущем) другие значки аналогичным образом (возможно, для других компонентов - я не знаю).


Для тех, кто не знаком с 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 возвращает http://localhost:8080/2273e3d8ad9264b7daa5bdbf8e6b47f8.png") для пути url("http://localhost:8080/2273e3d8ad9264b7daa5bdbf8e6b47f8.png")

это далеко не идеально, но я использую веб-пакет, и я использую этот обходной путь

Я скопировал изображения в папку изображений в корне моего проекта.

затем в моем 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:

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, который добавляет хэш содержимого файла к имени статических файлов, поэтому marker-icon.png становится marker-icon.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;

а затем используя requireдля этой проблемы:

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

Обходной путь (с размером и привязкой) для

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-адреса изображения. При загрузке большого количества маркеров (в моем случае 1000) производительность заметно хуже для встроенных изображений base64.

Вот представление производительности Chrome devtools при загрузке 1000 значков маркеров в качестве внешних URL-адресов:

1000 markers icons as external URLs

Для сравнения, с 1000 значками маркеров в виде встроенного base64 (извините, обратите внимание на другой масштаб временной шкалы):

1000 markers icons as inlined base64 URLs

Как видно, по какой-то причине композиция слоя задерживается при использовании встроенных изображений, из-за чего вся загрузка занимает примерно секунду больше.

Для случайного использования это, вероятно, не имеет значения, но если вы используете много маркеров, это может быть актуально.

Предложение о том, как справиться с этой долгой перспективой:

  • Исправление № 5041 для устранения проблем, упомянутых в обзоре кода; это заставит встроенные значки работать из коробки
  • Зарегистрируйте предупреждение, если используются встроенные значки, чтобы указать, что это может быть не идеально

Другой вариант - вернуться к старому (0,7) методу определения пути к изображению, но мы знаем, что были другие проблемы, которые мы не могли решить.

Привет @perliedman!

Хорошее профилирование!
Он отвечает на все сомнения , я имел относительно вниз сторону повторного использования встроенных изображений.

Действительно, PR # 5041 можно было бы реорганизовать, чтобы Leaflet мог работать сразу же, когда изображения значков встроены в CSS (с помощью механизма сборки, такого как webpack).
Решение, которое я могу придумать (в основном похожее на упомянутый PR), предполагало бы создание 1 класса для каждого изображения, следовательно, оно увеличило бы размер файла CSS (и, вероятно, JS) на несколько десятков байтов.

Пример: http://playground-leaflet.rhcloud.com/dulox/1/edit?html , css, вывод

Но, как я упоминал ранее , очень жаль, что такое изменение по причине совместимости (с механизмами сборки) затрагивает пользователей, которые не используют эти платформы и процессы сборки.

С другой стороны, результат может быть «чище», поскольку мы могли избавиться от жестко закодированных имен файлов в параметрах класса IconDefault и делегировать полный путь (включая имя файла) CSS.
Это очень интересно, потому что (если я правильно понимаю) весь смысл этого сложного обнаружения состоит в том, чтобы отделить расположение изображений от файла JS и вместо этого полагаться на их относительное расположение к файлу CSS. Поэтому мне кажется логичным, что даже имя файла определено в CSS.

Но тогда попытка сохранить совместимость с опцией imagePath также может быть сложной, поскольку это, вероятно, потребует переделки путей к изображениям, которые были ранее обнаружены, чтобы заменить ведущий путь и сохранить имя файла. Поэтому мы бы представили там новый RegExp.

Наконец, я не уверен, что это охватит все случаи.
Процессы сборки можно настраивать, что приводит к очень разным ситуациям со статическими активами, такими как изображения значков. Все еще могут быть некоторые угловые случаи, когда даже вышеперечисленное не сработает.

@ghybs Мне нравится этот пример (http://playground-leaflet.rhcloud.com/dulox/)!

Возможно, вы переусердствуете, но что вы думаете об указании значка _size_ в этом CSS (с использованием width и height )? Я могу представить, как кто-то отменяет эти правила CSS, чтобы изменить значок по умолчанию, но обнаруживает, что теперь он имеет неправильные размеры.

С размерами в CSS или без них, я думаю, что это хороший путь вперед. Не хотели бы вы устроить пиар по вашему примеру? Если у вас сейчас нет времени или энергии, я могу пойти дальше и сделать это, просто скажите мне, что вы предпочитаете.

Я очень хочу закрыть эту, так как я сам случайно наткнулся на эту проблему.

Привет @perliedman!

Я согласен, что было бы даже лучше указать размер значка через CSS.

Но в этом случае для единообразия мы также должны указать точку привязки. Я не уверен, какое правило CSS подойдет для этого (может быть, маржа?). Если это возможно, то результат, я думаю, был бы очень хорошим: значки были бы полностью определены в CSS.

Если продолжить, это может быть дополнительным способом определения значка: укажите 3 класса CSS (значок, сетчатка, тень), и Leaflet извлечет из них все параметры значка.

Пожалуйста, не стесняйтесь работать над этим, я не уверен, когда, к сожалению, у меня будет время ...

Основываясь на предыдущем примере, вот концепция чтения правил padding и margin CSS для определения iconAnchor ( shadowAnchor ) и popupAnchor опции:
http://playground-leaflet.rhcloud.com/xuvi/1/edit?html , css, вывод

Мне не нравится тот факт, что я использовал padding для определения iconAnchor , потому что в конце Leaflet использует margin для размещения изображения значка ...
Но я обнаружил, что это самый простой способ быстро указать элементы в CSS и избежать возврата значений по сравнению с тем, как мы указываем параметры значков.

Хотя мне нравится результат указания всего в CSS, для поддержания обратной совместимости с L.Icon.Default.imagePath требуется еще больше работы.

Извиняюсь, не успел создать пиар.

Я только что диагностировал еще один случай, когда _detectIconPath не работает: при использовании Firefox (проверено с ESR и текущими версиями) и настройке Preferences → Content → Colors… → Переопределить цвета, указанные на странице, с выбранными выше: Всегда Firefox удалит background-image свойства, включая одно из .leaflet-default-icon-path и, таким образом, нарушают _detectIconPath .

Я не уверен, сколько других людей используют эту функцию Firefox, но я использую ее очень давно.

Можно ли использовать url() как значение других свойств CSS? Как использовать следующий CSS: .leaflet-default-icon-path { -leaflet-icon: url(images/marker-icon.png); } или невозможно самостоятельно определить и использовать пользовательские свойства CSS? Ни одному браузеру не нужно _ понимать_ свойство -leaflet-icon , однако им все равно нужно будет заполнить его и сделать его значение доступным для скриптов.

Привет @roques!

Благодарим вас за сообщение об этой проблеме при использовании этой конкретной опции в Firefox!
Похоже, в Chrome есть расширение High Contrast, но оно меняет только цвета, ничего не ломая в Leaflet.

К сожалению, Firefox удаляет свойства CSS, которые он не понимает.
Однако тип данных CSS изображения может использоваться с несколькими другими правилами, включая cursor , который выглядит нормально, даже если в Firefox используется параметр переопределения цветов:
http://playground-leaflet.rhcloud.com/yov/1/edit?html , css, вывод

Мне менее элегантно использовать cursor вместо background-image , поскольку его использование намного дальше от того, что мы сделали бы, чтобы сделать маркер с помощью стиля CSS ... но в любом случае это уже хак для пути только обнаружение.

Я собирался сделать пиар, чтобы решить проблему с веб-пакетом, я включу этот обходной путь прямо сейчас.
Я понятия не имею, как мы можем сделать автоматический тест для этого случая, но я думаю, что обходной путь уже должен быть хорошим.

Кто-нибудь нашел четкое решение этой проблемы?

Основываясь на ответе @ 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 :

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

Это скопирует значки в папку с ресурсами в папке dist во время сборки (вы не увидите их в 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, который был открыт с запрошенными изменениями в течение _длительного_ времени.

У нас также есть альтернативное решение # 5771, которое неплохо, но требует дополнительных изменений.

Итак, подведем итог: никто не представил принятый PR для решения этой проблемы, помощь приветствуется!

@perliedman, судя по всему, необходимы задействованные изменения # 5771. В противном случае эта проблема будет возникать при других обстоятельствах. Почему бы просто не слить это?

Привет @ mb21 ,

необходимы задействованные изменения № 5771

Фактически предлагаемые изменения бывают двух типов:

  • чтение каждого пути к изображениям, а не только расположения папки изображений, так что URL-адреса, измененные механизмами сборки (например, загрузчиком файлов webpack), читаются как есть, а не реконструируются / угадываются.
  • чтение всех остальных параметров значков по умолчанию из CSS, чтобы вся конфигурация была собрана в одном месте.

Второй пункт интересен, если первого нельзя избежать, даже если он добавляет довольно много кода.

Первый вариант на самом деле является преимуществом для разработчиков, использующих движок сборки, который возится с URL-адресами в CSS. Он сохраняет Leaflet _zero config spirit_ даже в новой среде, где разработчик тратит некоторое время на настройку своей конфигурации (если вы используете загрузчик файлов webpack, вам в любом случае потребуется настраиваемая конфигурация) за счет добавления некоторого кода для всех остальных, который это IMHO _against_ Leaflet spirit (поддержка общего использования в ядре, делегирование других вариантов использования плагинам).
Вы можете очень легко решить проблему, в первую очередь, указав пути к изображениям, обычно используя require(image) как показано в многочисленных комментариях выше.

Поэтому, несмотря на то, что я написал этот PR, мне лично неудобно объединять его в ядро. Изменения _не нужны для большинства_.

Они, безусловно, хороши, чтобы облегчить жизнь разработчикам, но проблема в первую очередь вызвана взаимодействием механизмов сборки / оболочек фреймворка, каждая из которых имеет свои особенности, и у каждой есть простой способ сообщить Leaflet, где сейчас находятся изображения, используя уже существующие API.

Может быть, нам лучше решить эту проблему с помощью более качественной документации (например, раздела, посвященного использованию с движками / фреймворками сборки?) И / или плагином?

Что ж, я не уверен, что разбираюсь в тонкостях. Но для всех разработчиков было бы неплохо, если бы _все_ пути к изображениям могли быть указаны в CSS. Это не только пользователи webpack, но и такие люди, как я, использующие конвейер ресурсов Rails или Django, который добавляет хэш к каждому статическому активу ...

У меня возникла точно такая же проблема:
data: image / png; base64, iVBORw0 ... AAAAASUVORK5CYII = ") 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 был загружен № 1 с unpkg CDN, то есть с разделенным и незакрепленным CSS.

Правильным решением является определение параметров значка по умолчанию, как объяснено во многих сообщениях выше.
Многие фреймворки делают это как часть своего плагина интеграции Leaflet.

Если вам нужно более автоматическое решение, у вас все еще есть возможность опубликовать плагин.

Почему бы не слить PR?

Прочтите комментарии, например https://github.com/Leaflet/Leaflet/issues/4968#issuecomment -382639119

Я просто хотел бы сделать небольшой намек: вы можете использовать CDN также при использовании фреймворка. Это то, что мы делаем, например, с нашим приложением React. Загружаем большие библиотеки через CDN.

@ googol7 спасибо за ваш вклад.

Пожалуйста, поправьте меня, если я ошибаюсь: если вы загружаете Leaflet через CDN, это, скорее всего, означает, что вы не меняете его 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 благодарим вас за подробности вашей конфигурации.

Вы имеете в виду, что загружаете Leaflet JS из CDN, но объединяете CSS и изображения в свое приложение.

@ghybs да, думаю, вот что здесь происходит.

Обязательно выполните первые два шага: https://leafletjs.com/examples/quick-start/
У меня была аналогичная проблема, потому что я использовал 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 Default Icon больше не пытается перестроить пути к изображениям значков, а полностью полагается на 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. Помещать это как плагин далеко не идеально, ИМХО, поскольку я не вижу людей, которые ищут плагин для решения этой проблемы (как и я, когда открывал дубликат).
Я бы очень хотел увидеть эту листовку внутри, так как это скорее исправление ошибки, чем функция ...

Если вы хотите решить эту проблему в 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

ЗАМЕТКА:
Существует небольшой улов в угловых 6, как ответ от _t.animal_ на StackOverflow говорит

Имейте в виду, что в Angular 6 есть два соответствующих конструктора в архитекторах build и test .

Убедитесь, что вы поместили его под build .

@ marko-jovanovic спасибо за информацию, но что, если я не использую эти ресурсы и хочу уменьшить размер своего пакета?
Ваше предложение все еще подпадает под мое определение обходного пути, ИМО.

@HarelM Что ж, я не мог

@ marko-jovanovic, ваше решение отличное, и я тоже надеюсь, что оно поможет другим. Я просто надеюсь на решение, а не на обходной путь :-)

@ marko-jovanovic Привет, я слишком занят школьным проектом (Angular 6) и не могу понять, почему у меня что-то не работает. Если честно, я абсолютный новичок во всем этом здесь.

Когда я вставляю ваш код в ngOnInit -функцию моего компонента, он выдает ошибку в той части, где вы устанавливаете iconUrl и 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'.

Я что-то упускаю? Заранее спасибо!

@gittiker Я обновил ответ примером импорта, компонента и ngOnInit. Дай мне знать, если все пойдет хорошо. :)

@gittiker Я обновил ответ примером импорта, компонента и ngOnInit. Дай мне знать, если все пойдет хорошо. :)

Да, большое спасибо, наконец-то работает. Мне пришлось немного изменить ваш URL-адрес, поэтому он
'assets/leaflet/images/marker-icon.png вместо 'assets/leaflet/marker-icon.png', . То же самое и с теневым изображением.

@ crob611 Большое спасибо, попробовал решить проблему этим методом.

@ marko-jovanovic, ты меня спас! но как говорит @HarelM , разве нет решения?

большое спасибо, но для меня он служил следующим кодом: (Angular 6 и листовка1.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-листом 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 цента: моя проблема с веб-пакетом была связана только с хешированными именами файлов, поэтому я настроил 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 благодарит за исправление. Я несколько раз сталкивался с этой ошибкой в ​​разных проектах. Вся эта цепочка кажется абсурдной, потому что она не исправлена ​​или не рассматривается как проблема.

Google привел меня сюда, потому что использование библиотеки с Webpack давало мне эту ошибку.

Кто-нибудь знает, почему эти изображения не встроены как svg?

Я думаю, это можно легко решить с помощью postcss и postcss-inline-svg . Значки станут встроенными в файлы svg вместо внешних png . Значки будут более четкими, поскольку эта проблема исчезнет.

Кто-нибудь знает, почему эти изображения не встроены как svg?

Поддержка устаревшего браузера.

Спасибо @IvanSanchez

Тогда я вижу два возможных решения. Один из них - встроить изображения в кодировку base64 .png . Другая альтернатива - встроить значки .svg и заставить разработчиков, ориентированных на устаревшие платформы, переопределить значки по умолчанию.

Стоит ли какое-либо из этих решений запрашивать вытягивание?

Из всех браузеров, поддерживаемых листовкой , следующие не поддерживают svg ( caniuse ).

  • IE 7 и 8
  • Браузер Android 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, поэтому все элементы должны находиться в статической папке), но исправления @ giorgi-m недостаточно, так как я получаю ошибку «экспорт» доступен только для чтения ( Firefox, похоже, связан с импортом png?).
Я вижу, что проблема закрыта, но мы все еще наблюдаем проблемы с 1.4.0, поэтому мне интересно, что это за исправление?

Увидев эту проблему с vue2-листовкой 2.0.2 и листовкой 1.4.0.

похоже, что это существует довольно давно, и половина представленных решений, похоже, не работает.

Кто-нибудь разобрался в корне этой проблемы?

У меня такая же проблема с версиями "vue2-leaflet": "2.0.3" leaflet "leaflet": "1.4.0".

также работает webpack.

Мы успешно используем vue2-листок 2.0.3 и листок 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

Хотя я понимаю, что многие разработчики предпочли бы, чтобы такая функция была включена непосредственно в ядро ​​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 рейтинги