Leaflet: السماح للإزاحة في وسط الخريطة.

تم إنشاؤها على ٣١ يوليو ٢٠١٢  ·  31تعليقات  ·  مصدر: Leaflet/Leaflet

أهلا. سيكون من الرائع للغاية أن تكون قادرًا على موازنة مركز الخريطة بالنسبة إلى منفذ العرض. حالة الاستخدام الرئيسية لدي هي أن لدي مربعًا كبيرًا يتراكب على الخريطة على اليسار ، وأود أن يكون مركز الخريطة أكثر جهة اليمين. هذا يعني أنه عندما أقوم بتحريك أو توسيط ، فسيتم تعويض مقدار معين من البكسل أو نسبة مئوية من منفذ العرض. سيكون هذا إعداد مستوى الخريطة.

لقد أردت هذه الميزة في العديد من مكتبات تعيين JS لكنني لم أجدها بعد. لسوء الحظ ، يجب أن يكون المستوى منخفضًا جدًا في واجهة برمجة التطبيقات.

عذرًا ، ليس لدي أي رمز ، كنت أفكر فقط وأردت إزالته.

شكرا على المشروع الرائع!

feature

التعليق الأكثر فائدة

إليك كيفية تنفيذي حاليًا لـ panTo مع الإزاحة في مشروعنا على https://github.com/codeforamerica/lv-trucks-map (موقع مباشر على http://clvfoodtrucks.com/). يقوم بتعديل كائن النموذج الأولي L.map بحيث تكون هذه الطريقة متاحة "أصلاً" على كائنات الخريطة ، ويجب إضافتها إلى كود JavaScript قبل إنشاء الخريطة:

L.Map.prototype.panToOffset = function (latlng, offset, options) {
    var x = this.latLngToContainerPoint(latlng).x - offset[0]
    var y = this.latLngToContainerPoint(latlng).y - offset[1]
    var point = this.containerPointToLatLng([x, y])
    return this.setView(point, this._zoom, { pan: options })
}

وهي تعمل بنفس طريقة panTo () ولكن مع معلمة إضافية ، offset ، وهي مصفوفة في شكل [xOffset, yOffset] . يمكنك تعديل هذا لإنشاء طريقة setViewOffset () أيضًا.

ال 31 كومينتر

إنه في الواقع سهل جدًا في Leaflet. ما تحتاجه هو طريقة map.containerPointToLatLng . يقوم بتحويل بعض إحداثيات البكسل المتعلقة بالركن الأيسر العلوي من الخريطة إلى موقع جغرافي. إذن أنت تفعل شيئًا كهذا:

var centerPoint = map.getSize().divideBy(2),
    targetPoint = centerPoint.subtract([overlayWidth, 0]),
    targetLatLng = map.containerPointToLatLng(centerPoint);

map.panTo(targetLatLng);

هل هذا يحل حالة الاستخدام الخاصة بك؟

يا. إنه نوع ما ، وربما يكون جيدًا بما يكفي. لكن المشكلة هنا هي أنها تفترض أن منفذ العرض هو المكان الذي تريد توسيطه ، ثم يعوضه ، لذلك ستكون حركة من خطوتين. على عكس أخذ lat-lng ، والإزاحة ، ثم بالغسل ؛ حركة واحدة.

أوه ، حساباتي غير صحيحة. تحتاج إلى تعيين مركز الخريطة الفعلي بحيث يكون مركز الإزاحة في النقطة المستهدفة ، وسوف يساوي الإزاحة overlayWidth / 2 . إذن ، هذا هو رمز العمل لحركة واحدة:

var targetPoint = map.project(targetLatLng, targetZoom).subtract([overlayWidth / 2, 0]),
    targetLatLng = map.unproject(targetPoint, targetZoom);

map.setView(targetLatLng, targetZoom);

هذه هي الحالة نفسها التي كانت لدينا أيضًا - شريط جانبي معتم قليلاً متراكب أعلى الخريطة. كلما أطلقنا على fitBounds () ، سيكون الأمر بعيدًا بعض الشيء وسنحتاج إلى القيام بحركة أخرى من أجل تصحيحها. كنا نفكر في طلب سحب لهذا ولكن انتهى بنا المطاف فقط بتحريك الشريط الجانبي ليكون بجوار الخريطة حيث اعتقدنا أنه قد يكون قليلًا من العمل ولم نعتقد أنه كان حالة استخدام شائعة بدرجة كافية.

mourner هذا منطقي للغاية. أعتقد فاتني طرق المشروع (). هذا لا يتعامل مع معظم حالات الاستخدام الخاصة بي. تشكرات.

مثل ajbeaven ، فإن طبقة FitBounds لطبقة (GeoJSON) ستكون رائعة للغاية ، ولكن يبدو أن هذا سيكون أكثر تعقيدًا. لا أعتقد أن مجرد الموازنة أمر جيد بما فيه الكفاية ، حيث تتغير حدود إطار العرض بشكل فعال ، ولا أعرف كيفية القيام بذلك في مكالمة واحدة.

في كلتا الحالتين ، لا تتردد في إغلاق ذلك إذا لم يكن من المنطقي الإضافة في المكتبة نفسها. أعتقد أنه يمكنني إدارة مشروعي المحدد باستخدام الكود الذي قدمته. شكرا.

fitBounds مطول أكثر قليلاً ولكنه سهل أيضًا. ما عليك سوى نسخ https://github.com/CloudMade/Leaflet/blob/master/src/map/Map.js#L275 ولصقه ، وتعديل الحجم الذي تستخدمه ، ثم استخدم

var targetZoom = altGetBoundsZoom(map, bounds);
// ... calculate targetLatLng as above
map.setView(targetLatLng, targetZoom);

أهلا. أنا أستخدم fitBounds مع LatLng[] كمعامل وحاولت استخدام مقتطفات التعليمات البرمجية التي قدمتها أعلاه ، ولكن دون جدوى.
يحتوي موقع الويب الخاص بي على تراكب شريط جانبي حيث أريد أن تكون الخريطة مرئية تحتها ، لكني أرغب في منع ظهور العلامات أسفل هذا التراكب. (سيكون من الرائع تعويض مركز الخريطة أيضًا ، ولكن يمكن القيام بذلك يدويًا.)

هل يمكنك من فضلك نشر مقتطف شفرة كامل لـ fitBounds على _offset map_؟
أنا في حيرة من أمري مما كتبته أعلاه. المشكلة هي أنه ليس لدي أي targetLatLng ولا targetPoint أستخدم مصفوفة من النقاط.

بالمناسبة. سيكون من الرائع حقًا أن يكون لديك خيار لتحديد مقدار المساحة شبه المتراكبة على كل جانب من الحاوية ، حيث ما زلت ترسم الخريطة ، لكنك لن تضع أي عناصر تحكم على العلامات هناك.

يمكنك رؤية الكود الذي قمت بتطبيقه هنا. (إنها ليست بأي حال من الأحوال مثالًا رائعًا للكود ، ولكن الفكرة موجودة) كما أنها مضمنة في كائن يحمل خاصية الخريطة وهي خريطة Leaflet. لديها الطرق التالية:

appSetView
appSetBounds
appGetBoundsZoom

https://github.com/MinnPost/minnpost-my-boundaries/blob/master/visualizations/index.html#L556

إعادة الفتح ، حيث سيكون من المفيد إضافة هذه الوظيفة المضمنة.

صادفت هذه المناقشة حيث كان عليّ الحصول على قائمة على الجانب الأيسر من الشاشة بحجم 550 بكسل مع وجود الخريطة خلفها. قررت أنه سيكون من الأسهل على الأرجح تجاوز بعض الوظائف الأساسية لخريطة L.Map. شكرا على كل أفكارك.

آمل أن أكون قد غطيتهم جميعًا ، لكنني لست متأكدًا بنسبة 100٪.

MapCenterOffsetMixin = {
    UIOffset: [550, 0], // x, y
    getBounds: function(){
        var a=this.getPixelBounds(),
            b=this.unproject(new L.Point(a.min.x+this.UIOffset[0],a.max.y+this.UIOffset[1]), this._zoom,!0),
            c=this.unproject(new L.Point(a.max.x,a.min.y),this._zoom,!0);
            return new L.LatLngBounds(b,c)
    },
    _latLngToNewLayerPoint: function (latlng, newZoom, newCenter) {
        var targetPoint = this.project(newCenter, newCenter).subtract([this.UIOffset[0]/2, this.UIOffset[1]/2]),
            newCenter = this.unproject(targetPoint, newZoom);
        var topLeft = this._getNewTopLeftPoint(newCenter, newZoom).add(this._getMapPanePos());
        return this.project(latlng, newZoom)._subtract(topLeft);
    },
    _getCenterLayerPoint: function () {
        return this.containerPointToLayerPoint(this.getSize().divideBy(2).add([this.UIOffset[0]/2, this.UIOffset[1]/2]));
    },
    _resetView: function (a, b, c, d) {
        var e = this._zoom !== b;
        // Change the center
        var targetPoint = this.project(a, b).subtract([this.UIOffset[0] / 2, this.UIOffset[1]/2]),
            a = this.unproject(targetPoint, b);
        d || (this.fire("movestart"), e && this.fire("zoomstart")), this._zoom = b, this._initialTopLeftPoint = this._getNewTopLeftPoint(a);
        if (!c) L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
        else {
            var f = L.DomUtil.getPosition(this._mapPane);
            this._initialTopLeftPoint._add(f)
        }
        this._tileLayersToLoad = this._tileLayersNum, this.fire("viewreset", {
            hard: !c
        }), this.fire("move"), (e || d) && this.fire("zoomend"), this.fire("moveend"), this._loaded || (this._loaded = !0, this.fire("load"))
    }
}

L.Map.include(MapCenterOffsetMixin);

averrips شكرا لنشر ذلك. يعمل الحل الخاص بك بشكل جيد بالنسبة لي حاليًا ... فيما عدا أن عناصر التحكم في التكبير / التصغير معطلة في Firefox الآن :( أتلقى نوع الخطأ "الجامع": TypeError: t غير محدد

فيما يلي تطبيق لـ fitBoundsPadded ، والذي يجب أن يعيش في الخريطة:
استخدمه مثل fitBounds ، لكن مرر الحشوة التي تريدها ، لذا استخدمها مثل:

map.fitBoundsPadded(myBounds, new L.Point(0, 0), new L.Point(0, 150));

و الكود:

    fitBoundsPadded: function (bounds, paddingTopLeft, paddingBottomRight) { //(LatLngBounds, Point, Point)

        var zoom = this.getBoundsZoom(bounds);
        var zoomToTry = zoom;

        while (true) {
            var newTopLeft = this.unproject(this.project(bounds.getNorthEast(), zoomToTry).add(paddingTopLeft), zoomToTry);
            var newBottomRight = this.unproject(this.project(bounds.getSouthWest(), zoomToTry).add(paddingBottomRight), zoomToTry);

            var paddedBounds = new L.LatLngBounds([bounds.getSouthWest(), bounds.getNorthEast(), newTopLeft, newBottomRight]);

            var zoom2 = this.getBoundsZoom(paddedBounds);

            if (zoom2 == zoomToTry) {
                return this.fitBounds(paddedBounds);
            } else {
                zoomToTry--;
            }
        }
    },

نفذت في الماجستير! استخدمه مثل هذا:

map.fitBounds(bounds, [20, 30], [40, 50]); // bounds, topLeftPadding, bottomRightPadding

أو قم بتمرير الوسيطة الثانية فقط وسيتم تعيين المساحة المتروكة أسفل اليمين افتراضيًا لتساوي أعلى اليسار.

التوقيع تغير قليلا. الآن يمكنك استخدامه على النحو التالي:

map.fitBounds(bounds, {
    padding: [20, 30]
});

map.fitBounds(bounds, {
    paddingTopLeft: [20, 30],
    paddingbottomRight: [40, 50]
});

هل هناك أي عمل مخطط له لإضافة الحشو إلى وظائف أخرى؟

ربما نعم. مقابل setView و panTo على الأقل.

يجب أن يكون هناك اختصار لتطبيق نفس المساحة المتروكة على جميع الجوانب. شيء من هذا القبيل.

map.fitBounds(bounds, { padding: 20 });

بدلا من التيار ...

map.fitBounds(bounds, { padding: [20, 20] });

averrips أن Mixin كان مفيدًا جدًا ، شكرًا لك.

لم أتمكن من العثور على الحل بعد ، لذا ها أنت ذا (سهل جدًا):

 وظيفة recenter (map ، latlng ، offsetx ، offsety) {
 var centre = map.project (latlng) ؛
 المركز = نقطة L. الجديدة (center.x + offsetx ، center.y + offsety) ؛
 var target = map.unproject (مركز) ؛
 map.panTo (الهدف) ؛
 }

يرجى إضافة نفس الوظيفة أيضًا لـ "setView" و "panTo".
شكرا!

أيضًا ، هل هناك طريقة لحشو عناصر التحكم اليسرى | اليمنى؟

إليك كيفية تنفيذي حاليًا لـ panTo مع الإزاحة في مشروعنا على https://github.com/codeforamerica/lv-trucks-map (موقع مباشر على http://clvfoodtrucks.com/). يقوم بتعديل كائن النموذج الأولي L.map بحيث تكون هذه الطريقة متاحة "أصلاً" على كائنات الخريطة ، ويجب إضافتها إلى كود JavaScript قبل إنشاء الخريطة:

L.Map.prototype.panToOffset = function (latlng, offset, options) {
    var x = this.latLngToContainerPoint(latlng).x - offset[0]
    var y = this.latLngToContainerPoint(latlng).y - offset[1]
    var point = this.containerPointToLatLng([x, y])
    return this.setView(point, this._zoom, { pan: options })
}

وهي تعمل بنفس طريقة panTo () ولكن مع معلمة إضافية ، offset ، وهي مصفوفة في شكل [xOffset, yOffset] . يمكنك تعديل هذا لإنشاء طريقة setViewOffset () أيضًا.

شكرا لوه!

كمرجع ، يعمل هذا التكوين بالنسبة لي لمحاكاة الإزاحة الأفقية كما هو موضح في الصفحة الرئيسية لـ foursquare.
https://gist.github.com/missinglink/7620340

شكرا @ louh!

شكرا missinglink ، كودك يعمل!

هل يوجد حل أيضًا لعمليات التكبير / التصغير؟

أنا أستخدم شيئًا كهذا:

        var MapCenterOffsetMixin = {
            getMapOffset: function() {
                console.log('getMapOffset');
                return [$('#left-panel').offset().left, 0];
            },
            getBounds: function(){
                console.log('getBounds');
                var offset = this.getMapOffset(),
                    bounds = this.getPixelBounds(),
                    sw = this.unproject(new L.Point(bounds.min.x + offset[0], bounds.max.y + offset[1]), this._zoom, !0),
                    ne = this.unproject(new L.Point(bounds.max.x, bounds.min.y), this._zoom, !0);

                return new L.LatLngBounds(sw, ne)
            },
            _oldLatLngToNewLayerPoint: L.Map.prototype._latLngToNewLayerPoint,
            _latLngToNewLayerPoint: function (latlng, newZoom, newCenter) {
                console.log('_latLngToNewLayerPoint');
                var offset = this.getMapOffset(),
                    targetPoint = this.project(newCenter, newCenter).subtract([offset[0] / 2, offset[1] / 2]);
                newCenter = this.unproject(targetPoint, newZoom);

                return this._oldLatLngToNewLayerPoint(latlng, newZoom, newCenter);
            },
            _getCenterLayerPoint: function () {
                console.log('_getCenterLayerPoint');
                var offset = this.getMapOffset();
                return this.containerPointToLayerPoint(this.getSize().divideBy(2).add([offset[0] / 2, offset[1] / 2]));
            },
            _oldResetView: L.Map.prototype._resetView,
            _resetView: function (center, zoom, preserveMapOffset, afterZoomAnim) {
                console.log('_resetView');
                var offset = this.getMapOffset(),
                    targetPoint = this.project(center, zoom).subtract([offset[0] / 2, offset[1] / 2]);
                center = this.unproject(targetPoint, zoom);

                this._oldResetView(center, zoom, preserveMapOffset, afterZoomAnim);
            }
        };
        L.Map.include(MapCenterOffsetMixin);

لكنه فشل في التكبير.

إليك الحل: https://github.com/Mappy/Leaflet-active-area. متألق! :)

يبدو أن وظيفة "map.fitBounds (bounds، topLeftPadding، bottomRightPadding)" تستخدم قيمًا لضبط خطوط الطول وليس وحدات البكسل. لذلك سيكون لمستويات التكبير المختلفة نتائج مختلفة حول مدى تعديل الخريطة. أنا متأكد من وجود حالة استخدام لهذا ، ولكن يبدو أنه بالنسبة للمشكلة التي يطرحها الجميع ، شريط جانبي بحجم معين أو قائمة عليا ، يجب ألا يعتمد الضبط على مستوى التكبير / التصغير. هل توجد وظيفة نشرة مضمنة تضيف حشوًا يعتمد على البكسل بدلاً من الإحداثيات؟

توقع قيم topLeftPadding و bottomRightPadding بالبكسل: http://leafletjs.com/reference.html#map -fitboundsoptions

لسبب ما لا يبدو أن هذا هو الحال بالنسبة لي. لاختبار ذلك ، أقوم بتوسيط علامة عند مستوى تكبير 15 ثم قم بتشغيل هذا الأمر ...
map.fitBounds(pointsArray, {paddingTopLeft: [0,0], paddingBottomRight: [800,0], maxZoom: map.getZoom()});
ثم أعد توسيط العلامة عند مستوى تكبير 19 وقم بتشغيله مرة أخرى. في المستوى 15 يكاد يكون غير ملحوظ المقدار الذي يتغير. ومع ذلك ، في المستوى 19 ، فإنه يتحول إلى أكثر من نصف الصفحة تقريبًا. هل أفعل شيئًا خاطئًا في مكالمة وظيفتي؟

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات