this.leafletMap = new L.Map( <element> , {
zoomControl: true,
dragging: this.isInDragMode,
touchZoom: false,
scrollWheelZoom: false,
doubleClickZoom: false,
tap: false,
}
L.tileLayer( 'http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
} ).addTo( this.leafletMap );
if (this.leafletMap ){
this.leafletMap.eachLayer(function(layer){
layer.remove();
});
this.leafletMap.remove();
this.leafletMap = null;
}
Uncaught TypeError: Cannot read property '_leaflet_pos' of undefined
استخدام http://playground-leaflet.rhcloud.com/ أو أي موقع آخر يشبه jsfiddle.
مرحبًا وشكرًا على الوقت الذي قضيته في الإبلاغ عن هذا الخطأ.
ومع ذلك ، يبدو أن هناك شيئًا مفقودًا من الخطوات التي تصفها لإعادة إظهار المشكلة. لقد قمت بإعداد مثال لملعب كما يمكنني القيام به على طول الخطوات أعلاه: http://playground-leaflet.rhcloud.com/rezop/edit؟html ، الإخراج
في هذا المثال ، لا يمكنني رؤية أي أخطاء بعد إزالة الخريطة ، لذلك يبدو أن هناك شيئًا آخر يحدث يسبب المشكلة التي تراها. هل يمكنك تقديم مزيد من التفاصيل ، حتى نتمكن من تعقب ذلك.
perliedman شكرًا للاستجابة السريعة ووضع مثال لملعب. لا أستطيع التكاثر على ذلك. تجربة عدد قليل من السيناريوهات. بينما ما زلت أبحث في الأمر ، بضعة أسئلة -
هل أحتاج إلى إزالة صريحة للطبقة ، إذا كنت أعمل map.remove()
؟ تخميني هو أنه سيهتم بإزالة الطبقة أيضًا ، لكن هل يمكنك التأكيد.
والسبب في وجود map.remove () تحت timeout هو أنك في المثال تقوم بتدمير الخريطة بعد الإنشاء مباشرةً ، وإلا فليس مطلوبًا إرفاقها بمهلة. صيح؟
تذكر ، عند العمل مع المصدر المفتوح ، استخدم المصدر! : wink: للإجابة على سؤالك الأول ، _yes_ ، remove
سيزيل الطبقات: https://github.com/Leaflet/Leaflet/blob/master/src/map/Map.js#L731
وكان السبب وضعه في مهلة لجعل بلدي على سبيل المثال قليلا أكثر واقعية، والتأكد من ان طبقة البلاط تهيئة الواقع بشكل صحيح مع البلاط تحميل، وما إلى ذلك المثال يعمل فقط كذلك دون تعريض remove
الدعوة في مهلة ، لكنها تبدو وكأنها اختبار مصطنع.
مرحبًا - أعتقد أنني أعاني من هذه المشكلة أيضًا. إليك حالة الاستخدام الأساسية الخاصة بي:
أقوم بإنشاء مكون عارض (باستخدام المكون الإضافي Leaflet-IIIF ، لكنني لا أعتقد أن هذا يؤثر على أي شيء هنا) للكائنات ذات الصفحات / الأسطح المتعددة بدلاً من عرض خريطة فعلية. عند تحميل العارض ، توجد سلسلة من الصور المصغرة التي يمكن للمستخدم النقر عليها لتحديث طريقة عرض الكائن التي يتم عرضها في المنطقة المركزية لواجهة المستخدم.
عندما يغير المستخدم العرض ، أتصل بـ map.remove()
قبل إعداد خريطة جديدة للعرض الجديد. تم إنشاء الخريطة الجديدة على نفس عنصر DOM مثل العنصر القديم (div بمعرف) ، وأنا لا أقوم بتعديل DOM بأي شكل من الأشكال خارج Leaflet.
في العرض الأولي كل شيء يعمل بشكل جيد. ولكن بعد استدعاء map.remove()
وإظهار طريقة عرض جديدة ، تشكو وحدة التحكم: Cannot read property '_leaflet_pos' of undefined
كلما تم سحب الخريطة أو تكبيرها.
يمكنني محاولة نشر مثال بسيط في وقت ما ، ولكن يبدو أن هذه هي نفس المشكلة. يظهر هذا الخطأ في Chrome وليس في Firefox.
egardner نعم ، يرجى محاولة إنشاء مثال يعيد إنتاج هذا!
egardner بالضبط نفس المشكلة على تطبيق الإلكترون المستقر سابقًا (Chromium + Node) الذي اضطررت إلى الرجوع إليه:
"نشرة": "1.0.0"،
"Leaflet.markercluster": "1.0.0-rc.1.0"
من 1.2.0 لإزالة الخطأ لا يمكن قراءة الخاصية '_leaflet_pos' من undefined
كان هذا أيضًا بعد map.remove () قبل إعادة إنشاء الخريطة في نفس عنصر DOM. ليس لدي الوقت الآن فقط للإبداع والمثال على المدى القصير
نحن نواجه أيضًا مشكلة مماثلة في محاولة تدمير خريطة ، يبدو أننا نتمسك بالمراجع
سأكرر ما قلته أعلاه: حتى نتمكن من فعل أي شيء حيال هذه المشكلة ، يرجى تقديم مثال يعيد إنتاج المشكلة.
أهلا. لقد كررت هذا الخطأ في كمان. ببساطة ، إذا قمت بإنشاء خريطة داخل عنصر div ، ثم استخدم طريقة الإزالة ، ثم أعد ملء الخريطة على نفس عنصر div ، ستؤدي كل حركة للخريطة بعد ذلك إلى حدوث خطأ
خطأ في النوع غير معلوم: لا يمكن قراءة الخاصية '_leaflet_pos' من undefined.
لإعادة الإنتاج ، افتح كمانتي ، وانقر على إزالة الخريطة ، وانقر على خريطة المكان ، ثم افتح وحدة التحكم وحرك الخريطة.
http://jsfiddle.net/spydmobile/5hmadjnk/
لاحظ أن هذا يحدث فقط في Chorme ، وليس في FF
نعم ، شكرًا spydmobile على المثال ، هذا هو الخطأ نفسه الذي أراه في Chrome كما ذكرت أعلاه
أرى نفس الخطأ ولكن في حالة استخدام مختلفة قليلاً. تم طرح نفس الخطأ عند تغيير الحجم بسبب مكالمة invalidateSize
:
Uncaught TypeError: Cannot read property '_leaflet_pos' of undefined
at getPosition (leaflet-src.js:2765)
at NewClass._getMapPanePos (leaflet-src.js:4378)
at NewClass._rawPanBy (leaflet-src.js:4180)
at NewClass.invalidateSize (leaflet-src.js:3509)
at NewClass.<anonymous> (leaflet-src.js:4244)
يبدأ مكدس الاستدعاءات الكامل عند معالج _onResize
. أنا أستخدم react-leaflet
لكن لا يوجد أي جزء من تتبع المكدس يشير إلى ذلك أو أن الرمز المحلي هو المشكلة. لقد جربت عددًا قليلاً من الإصدارات القديمة (مثل 1.0.3
و 1.2.0
) معتقدًا أننا قد نكون قادرين على الأقل على تأمينه على إصدار 1.x.x
، لكن لم يحالفني الحظ.
هل هناك أي تحديث على ذلك؟ أواجه نفس المشكلة هنا دمج النشرة في طلبي. بعد تدمير الخريطة ، لا يزال عنصر dom يحتوي على خاصية _leaflet_events ، لكن التخلص من هذا الكائن لم يساعد أيضًا.
يبدو أن سياق دالة المعالج لا معنى له (تشير الخاصية الخاصة _mapPane في أرغس المعالج إلى عنصر غير موجود).
أنا أواجه هذا أيضًا. هذا أحد الاستثناءات الملقاة التي أراها:
https://sentry.io/share/issue/b414c58ea85c44ee9e0e40ad0781883a/
يبدو أن هذا يحدث غالبًا عندما يستخدم المستخدم زر الرجوع في المتصفحات لمغادرة الخريطة.
أعتقد أنني قد وجدت الحل:
لا يزال لدى حاوية الخريطة div بعض الأحداث التي يتم تشغيلها حتى بعد map.off
و map.remove
.
في حالتي ، تحتوي الخريطة على خصائص تبدأ بـ _leaflet_
وبعض هذه الوظائف وجدت أنها موجودة على الخريطة نفسها في الخاصية "map._leaflet_events".
يبدو أنها مرفقة كـ pointerdown
، pointermove
map._leaflet_touchstarttouchstart32
وهكذا لكن أسماء الخصائص مثل
لقد وجدت أنه إذا قمت بتكرار هذه الأشياء وإزالتها يدويًا (باستخدام removeEventListener
ثم إلغاء وحذف الخاصية نفسها كمقياس جيد) ، يمكنني إعادة استخدام div لخريطة أخرى.
هذا أيضًا وضع حدًا لتسريبات الذاكرة التي كنت أراها.
لا يمكنني كتابة الكود هنا ، ولكن إذا بحثت في مصدر المنشور عن POINTER_DOWN
سترى الأحداث المرفقة ، وتعرف كيفية فصلها.
يمكنني إعادة إنتاج هذا على Chrome ولكن أيضًا في FF (سواء في مشروعي الخاص أو باستخدام jsfiddle المقدم منspydmobile)
FLoibl ربما يتم نشر جوهر أو كمان أو بعض المقتطف في مكان آخر لتوضيح التقنية التي تستخدمها بنجاح
spydmobile هنا يذهب ، هذا ما فعلته بصيغة معدلة قليلاً:
ليس لدي أي فكرة عن كيفية إرسال الرمز بشكل صحيح في حقل التعليق هذا ، آسف لذلك.
لقد قمت بتحرير تعليقي الخاص حوالي 10 مرات الآن لول
function removeMap()
{
var leafletCtrl = get_your_own_leaflet_reference_from_somewhere(),
dom = leafletCtrl.getReferenceToContainerDomSomehow();
//This removes most of the events
leafletCtrl.off();
//After this, the dom element should be good to reuse, unfortunatly it is not
leafletCtrl.remove();
var removeDanglingEvents = function(inputObj, checkPrefix)
{
if(inputObj !== null)
{
//Taken from the leaflet sourcecode directly, you can search for these constants and see how those events are attached, why they are never fully removed i don't know
var msPointer = L.Browser.msPointer,
POINTER_DOWN = msPointer ? 'MSPointerDown' : 'pointerdown',
POINTER_MOVE = msPointer ? 'MSPointerMove' : 'pointermove',
POINTER_UP = msPointer ? 'MSPointerUp' : 'pointerup',
POINTER_CANCEL = msPointer ? 'MSPointerCancel' : 'pointercancel';
for(var prop in inputObj)
{
var prefixOk = checkPrefix ? prop.indexOf('_leaflet_') !== -1 : true, propVal; //if we are in the _leaflet_events state kill everything, else only stuff that contains the string '_leaflet_'
if(inputObj.hasOwnProperty(prop) && prefixOk)
{
//Map the names of the props to the events that were really attached => touchstart equals POINTER_DOWN etc
var evt = [];
if(prop.indexOf('touchstart') !== -1) //indexOf because the prop names are really weird 'touchstarttouchstart36' etc
{
evt = [POINTER_DOWN];
}
else if(prop.indexOf('touchmove') !== -1)
{
evt = [POINTER_MOVE];
}
else if(prop.indexOf('touchend') !== -1)
{
evt = [POINTER_UP, POINTER_CANCEL];
}
propVal = inputObj[prop];
if(evt.length > 0 && typeof propVal === 'function')
{
evt.each(function(domEvent)
{
dom.removeEventListener(domEvent, propVal, false);
});
}
//Reference B-GONE, Garbage b collected.
inputObj[prop] = null;
delete inputObj[prop];
}
}
}
};
removeDanglingEvents(dom._leaflet_events, false);
removeDanglingEvents(dom, true);
}
آه ثلاثية باكتيكس ، فهمت ، تاي.
FLoibl هذا تحقيق جيد جدًا: +1:
هل يمكنك إضافة بعض قطع الأشجار حول ...؟ https://github.com/Leaflet/Leaflet/blob/5161140e952969c5da27751b79154a2c93f53bfa/src/dom/DomEvent.Pointer.js#L39 و https://github.com/Leaflet/Leaflet/blob/fe9e0f2333888e/ شبيبة # L133
يجب أن يتم تشغيلها لكل حدث عندما يتم تدمير L.Map
، ويجب أن تفعل نفس الشيء الذي تفعله ، لكنني أتساءل لماذا لا يعمل كما هو متوقع.
نعم ، أعرف هذه الوظيفة وأرى أنه يتم استدعاؤها ، ولكن ليس لجميع الأحداث.
أعتقد أن المشكلة تكمن في أن الكود يرفقهم كـ "pointermove" وما إلى ذلك إلى dom ، لكن أسماء الخصائص هي "touchstart" وما إلى ذلك أيضًا ، كما تظهر كلمة "touchstart" مرتين في اسم الخاصية ، وربما تكون سلسلة doube غير متوقعة من معرف واسم الحدث؟
هل يجب أيضًا إرفاق أحداث "المؤشر" هذه على نظام التشغيل Windows 10 بدون شاشة تعمل باللمس وفي Chrome؟
للأسف ، لا أعرف ما يكفي عن الأعمال الداخلية للمنشورات لتوفير حل حقيقي :-(
أعرف هذه الوظيفة وأرى أنه يتم استدعاؤها ، ولكن ليس لجميع الأحداث.
السؤال الآن هو: ما هي الأحداث التي لم يتم استدعاء removePointerListener
أجلها؟ ربما نفتقد استدعاء دالة هنا أو هناك.
هل يجب أيضًا إرفاق أحداث "المؤشر" هذه على نظام التشغيل Windows 10 بدون شاشة تعمل باللمس وفي Chrome؟
نعم فعلا. يكاد يكون من المستحيل اكتشاف ما إذا كان النظام يحتوي على شاشة تعمل باللمس ، لذلك إذا كان المتصفح يدعم أحداث المؤشر ، فإن الافتراض هو أنه سيتم استخدامها.
لا أعرف ما يكفي عن الأعمال الداخلية للمنشورات لتقديم حل حقيقي :-(
مرحبًا ، لا تيأس ، هذا عمل تحقيق رائع! :ابتسامة:
هذا الخطأ غير موجود في الإصدار 1.0.3. التقطت spydmobile jsfiddle وقمت بتغيير إصدار المنشور واختفى الخطأ http://jsfiddle.net/5hmadjnk/47/ . مع الإصدار 1.1.0 يوجد بالفعل.
@ benru89 كان هذا الخطأ موجودًا في الواقع في 1.0.3 ، في شكل https://github.com/Leaflet/Leaflet/issues/5263 (تم إصلاحه غالبًا بواسطة https://github.com/Leaflet/Leaflet/pull/ 5265).
أثر التغيير من 1.0.3 إلى 1.1.0 أيضًا على L.Mixin.Events
الذي تم إهماله الآن وبناء rollupJS ، لذلك لا أعتقد أنه يمكن تتبع ذلك بشكل جيد ، ولا حتى مع git bisect
.
IvanSanchez لقد قارنت وظيفة الإزالة في 1.0.3 و 1.1.0 وأضيف هذا:
for (i in this._panes) {
remove(this._panes[i]);
}
this._layers = [];
this._panes = [];
delete this._mapPane;
delete this._renderer;
إذا قمت بإزالة السطر السادس ، فسيتم حذف الخط الذي يحذف الخريطة. لا أعرف مع ذلك تأثير إزالة هذا ، أعتقد أنه يجب حذف MapPane ولكن تم تقديم هذا الخطأ بالتأكيد عند إضافة هذا السطر.
@ benru89 واو ، هذه أيضًا معلومات جيدة: +1:
أنا فقط لا أرى معالجات أحداث المؤشر الموجودة في أجزاء الخريطة في الوقت الحالي ، على الرغم من: التفكير:
أعتقد أنه من خلال عدم إزالة جزء الخريطة ، فإنك تخفي المشكلة فقط. عندما تعقبت مكدس الاستدعاءات ، كانت المشكلة أن بعض كائن _mapPane كان يشير إلى عنصر dom مدمر وبالتالي يحاول الحصول على موضع مخبأ من غير معرف. إذا لم يتم إتلاف الجزء ، فقد تمر أحداث الشبح دون تشغيل الاستثناء.
Floibl أتفق معك ، أعتقد أنه ليس هو الحل ، لكنني لاحظت أن null _mapPane عند فحص مكدس المكالمات ، ولهذا السبب حاولت عدم إزالة هذا السطر. يجب أن يكون الحل إلى جانب إزالة معالجات الأحداث بشكل صحيح على ما أعتقد.
أعتقد أن معالج الحدث الذي تسبب في حدوث ذلك (على الأقل في حالتي و spydmobile ) يسمى "touchExtend" لذا فهو معالج رسومات المنشور. اكتشفت أن إزالة الاستيراد للنشرة.رسم يوقف الاستثناءات أيضًا.
لقد وجدت حلاً آخر. يؤدي بدء تشغيل خريطتك باستخدام الخيار غير الموثق touchExtend : false
إلغاء تنشيط المعالج الإشكالي ، لذلك لا مزيد من الاستثناءات. لا أعرف حقًا الميزات التي أفقدها من خلال القيام بذلك ولكن بالنظر إلى الكود ، فقد تكون بعض الإيماءات الموسعة للجوال أو الشاشات التي تعمل باللمس ؟؟ على أي حال ، يبدو أن كل شيء في تطبيقي يعمل بشكل جيد.
IvanSanchez لست متأكدًا من أنها نفس المشكلة ، ولكن يمكن أن تكون ذات صلة.
عندما تدمر الخريطة عندما تكون حركة التكبير / التصغير قيد التقدم ، تحصل على الخطأ نفسه: Uncaught TypeError: Cannot read property '_leaflet_pos' of undefined
.
حاولت النظر داخل الكود ووجدت أنه يوجد داخل Map._animateZoom()
سطر: setTimeout(Util.bind(this._onZoomTransitionEnd, this), 250);
إذا فهمت ذلك بشكل كافٍ ، فلن يتم إتلاف هذه المهلة عند إزالة الخريطة ، لذلك يتم دائمًا استدعاء الوظيفة Map._onZoomTransitionEnd
. يمكن أن يكون _ "فقدان استدعاء دالة هنا أو هناك" _.
وشجرة الاتصال المبسطة this._onZoomTransitionEnd
-> this._move
-> this._getNewPixelOrigin
-> this._getMapPanePos
-> getPosition(this._mapPane)
-> return el._leaflet_pos
فشل this._mapPane
_undefined_.
ربما يمكن إصلاح هذه الحالة ، إذا قمت بلف المكالمات this._move
و this._moveEnd
في حالة if (this._mapPane) {}
، لكنني لم أختبر ما إذا كان لها بعض النتائج الأخرى.
استبدل هذا:
_onZoomTransitionEnd: function () {
if (!this._animatingZoom) { return; }
if (this._mapPane) {
removeClass(this._mapPane, 'leaflet-zoom-anim');
}
this._animatingZoom = false;
this._move(this._animateToCenter, this._animateToZoom);
// This anim frame should prevent an obscure iOS webkit tile loading race condition.
requestAnimFrame(function () {
this._moveEnd(true);
}, this);
}
مع هذا:
_onZoomTransitionEnd: function () {
if (!this._animatingZoom) { return; }
this._animatingZoom = false;
if (this._mapPane) {
removeClass(this._mapPane, 'leaflet-zoom-anim');
this._move(this._animateToCenter, this._animateToZoom);
// This anim frame should prevent an obscure iOS webkit tile loading race condition.
requestAnimFrame(function () {
this._moveEnd(true);
}, this);
}
}
أي تحديثات على هذا؟ أواجه نفس المشكلة. touchExtend : false
لا يساعد. تحدث المشكلة عندما أتنقل بعيدًا عن العرض ، حيث لدي الخريطة (يتم تدميرها في هذه المرحلة عن طريق استدعاء map.remove ()) ثم انتقل مرة أخرى إلى طريقة العرض هذه. يجب إنشاء الخريطة الجديدة وتهيئتها ، لكنني أتلقى الخطأ "_leaflet_pos" عند getPosition
في طريقة setMaxBounds
:
Uncaught (in promise) TypeError: Cannot read property '_leaflet_pos' of undefined
at getPosition (webpack-internal:///./node_modules/leaflet/dist/leaflet-src.js:2445)
at NewClass._getMapPanePos (webpack-internal:///./node_modules/leaflet/dist/leaflet-src.js:4409)
at NewClass._moved (webpack-internal:///./node_modules/leaflet/dist/leaflet-src.js:4413)
at NewClass.getCenter (webpack-internal:///./node_modules/leaflet/dist/leaflet-src.js:3774)
at NewClass.panInsideBounds (webpack-internal:///./node_modules/leaflet/dist/leaflet-src.js:3488)
at NewClass._panInsideMaxBounds (webpack-internal:///./node_modules/leaflet/dist/leaflet-src.js:4220)
at NewClass.setMaxBounds (webpack-internal:///./node_modules/leaflet/dist/leaflet-src.js:3444)
وأيضًا في طريقة setView
:
Uncaught (in promise) TypeError: Cannot read property '_leaflet_pos' of undefined
at getPosition (leaflet-src.js?9eb7:2445)
at NewClass._getMapPanePos (leaflet-src.js?9eb7:4409)
at NewClass.containerPointToLayerPoint (leaflet-src.js?9eb7:3989)
at NewClass._getCenterLayerPoint (leaflet-src.js?9eb7:4446)
at NewClass._getCenterOffset (leaflet-src.js?9eb7:4451)
at NewClass._tryAnimatedPan (leaflet-src.js?9eb7:4526)
at NewClass.setView (leaflet-src.js?9eb7:3181)
نفس المشكلة بعد map.remove () ، أعد تعيين خريطتي واحصل على هذا الخطأ بالضبط
نفس المشكلة مع v1.6.0. إنها قضية معقدة
إليك SSCCE: https://jsfiddle.net/0oafw694/1/
في الأساس ، تشغيل الكود التالي ...
map = L.map('map');
map.setView(...);
map.setMaxBounds(...);
map.remove();
... يترك اثنين من مستمعي الأحداث مرفقتين:
moveend: (1) […]
0: Object { fn: _panInsideMaxBounds(), ctx: undefined } // from setMaxBounds
unload: (2) […]
0: Object { fn: _destroy() , ctx: {…} }
1: Object { fn: _destroyAnimProxy(), ctx: undefined }
zoomanim: (1) […]
0: Object { fn: _createAnimProxy(), ctx: undefined }
أعتقد أنه يتم التعامل مع zoomanim/_createAnimProxy
عبر unload/_destroyAnimProxy
، وبالتالي لا توجد مشكلة. لكن moveend/_panInsideMaxBounds
يحتاج إلى أن يكون غير مسجّل. سأقوم بإعداد العلاقات العامة ...
لقد انتهيت للتو من إنشاء div للخريطة التي تحتوي على معرف ديناميكي ، لذلك عندما يتعين علي إعادة استخدام div ، أقوم بإزالة () الخريطة الحالية من أجل تحرير الذاكرة (حتى مع استمرار وجود بعض الأحداث) ثم أعد رسم div بمعرف مختلف لذلك أقوم بإنشاء خريطة جديدة فيه.
أقوم أيضًا بتخزين جميع خرائطي في كائن ، حتى أتمكن من معالجتها وفقًا لمعرفها (لدي أكثر من خريطة واحدة مرئية في بعض الأحيان ، وكلها مع معرفات ديناميكية)
وفقًا لتجاربي مع المنشور ، مهما كانت الأحداث (على سبيل المثال ، moveend ، movestart ، إلخ) التي يتم التلاعب بها من قبل المطورين ، فإنها تغير سلوكهم الافتراضي وتبقى في الذاكرة أثناء تفريغ المنشور من dom.
لقد فعلت هذا: @moveend="()=>{enableRecenter = true}"
وهكذا ، بقي معالج "moveend" في الذاكرة أثناء تفريغ / إزالة الخريطة.
لقد أزلت عمليات التلاعب (تطبيقاتي الخاصة) لهذه الطرق من مكون الخريطة نفسه والآن توقف هذا الخطأ عن الظهور.
لذلك ، في الأساس ، لا تلمس طرق الخريطة على الإطلاق !!! بالطبع ، ما لم تكتشف المكتبة هذا السلوك وتقوم بإصلاح هذا الخطأ.
التعليق الأكثر فائدة
spydmobile هنا يذهب ، هذا ما فعلته بصيغة معدلة قليلاً:
ليس لدي أي فكرة عن كيفية إرسال الرمز بشكل صحيح في حقل التعليق هذا ، آسف لذلك.
لقد قمت بتحرير تعليقي الخاص حوالي 10 مرات الآن لول