源码分析之Leaflet中geo模块LatLngBounds

概述

LatLngBounds 类是 Leaflet 中用于表示地理坐标边界框的类,通常用于定义地图的可视区域或进行空间查询。它包含了两个 LatLng 对象,分别表示边界框的左下角和右上角。

源码分析

源码实现

LatLngBounds.js 源码实现和介绍如下:

// 构造函数:创建地理边界边框,表示由西南sw和东北ne定义的矩形区域
export function LatLngBounds(corner1, corner2) {
  if (!corner1) {
    return;
  }

  var latlngs = corner2 ? [corner1, corner2] : corner1;

  for (var i = 0, len = latlngs.length; i < len; i++) {
    this.extend(latlngs[i]);
  }
}

// LatLngBounds的原型上定义方法
LatLngBounds.prototype = {
  // 扩展边界以包含给定对象(点或者另一个矩形区域)
  extend: function (obj) {
    var sw = this._southWest,
      ne = this._northEast,
      sw2,
      ne2;
    if (obj instanceof LatLng) {
      sw2 = obj;
      ne2 = obj;
    } else if (obj instanceof LatLngBounds) {
      sw2 = obj._southWest;
      ne2 = obj._northEast;

      if (!sw2 || !ne2) {
        return this;
      }
    } else {
      return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this;
    }

    if (!sw && !ne) {
      this._southWest = new LatLng(sw2.lat, sw2.lng);
      this._northEast = new LatLng(ne2.lat, ne2.lng);
    } else {
      sw.lat = Math.min(sw2.lat, sw.lat);
      sw.lng = Math.min(sw2.lng, sw.lng);
      ne.lat = Math.max(ne2.lat, ne.lat);
      ne.lng = Math.max(ne2.lng, ne.lng);
    }

    return this;
  },
  // 缓冲扩展:按比例扩展边界,生成更大的边界
  pad: function (bufferRatio) {
    var sw = this._southWest,
      ne = this._northEast,
      heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
      widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;

    return new LatLngBounds(
      new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
      new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)
    );
  },
  // 获取边界框的中心点
  getCenter: function () {
    return new LatLng(
      (this._southWest.lat + this._northEast.lat) / 2,
      (this._southWest.lng + this._northEast.lng) / 2
    );
  },
  // 获取边界框的西南角
  getSouthWest: function () {
    return this._southWest;
  },
  // 获取边界框的东北角
  getNorthEast: function () {
    return this._northEast;
  },
  // 获取边界框的西北角
  getNorthWest: function () {
    return new LatLng(this.getNorth(), this.getWest());
  },
  // 获取边界框的东南角
  getSouthEast: function () {
    return new LatLng(this.getSouth(), this.getEast());
  },
  // 获取边界框的西边界
  getWest: function () {
    return this._southWest.lng;
  },
  // 获取边界框的东边界
  getEast: function () {
    return this._northEast.lng;
  },
  // 获取边界框的南边界
  getSouth: function () {
    return this._southWest.lat;
  },
  // 获取边界框的北边界
  getNorth: function () {
    return this._northEast.lat;
  },
  // 判断点或者边界是否完全在当前边界内
  contains: function (obj) {
    if (typeof obj[0] === "number" || obj instanceof LatLng || "lat" in obj) {
      obj = toLatLng(obj);
    } else {
      obj = toLatLngBounds(obj);
    }

    var sw = this._southWest,
      ne = this._northEast,
      sw2,
      ne2;

    if (obj instanceof LatLngBounds) {
      sw2 = obj.getSouthWest();
      ne2 = obj.getNorthEast();
    } else {
      sw2 = ne2 = obj;
    }

    return (
      sw2.lat >= sw.lat &&
      ne2.lat <= ne.lat &&
      sw2.lng >= sw.lng &&
      ne2.lng <= ne.lng
    );
  },
  // 相交判断,检查两个边界是否有重叠区域(包括边界接触)
  intersects: function (bounds) {
    bounds = toLatLngBounds(bounds);

    var sw = this._southWest,
      ne = this._northEast,
      sw2 = bounds.getSouthWest(),
      ne2 = bounds.getNorthEast(),
      latIntersects = ne2.lat >= sw.lat && sw2.lat <= ne.lat,
      lngIntersects = ne2.lng >= sw.lng && sw2.lng <= ne.lng;

    return latIntersects && lngIntersects;
  },
  // 重叠判断:检查两个边界是否有严格重叠区域(不包括边界接触)
  overlaps: function (bounds) {
    bounds = toLatLngBounds(bounds);

    var sw = this._southWest,
      ne = this._northEast,
      sw2 = bounds.getSouthWest(),
      ne2 = bounds.getNorthEast(),
      latOverlaps = ne2.lat > sw.lat && sw2.lat < ne.lat, // 纬度严格重叠
      lngOverlaps = ne2.lng > sw.lng && sw2.lng < ne.lng; // 经度严格重叠

    return latOverlaps && lngOverlaps;
  },
  // 边界字符串:将边界框转换为字符串形式,通常用于URL参数或调试输出
  toBBoxString: function () {
    return [
      this.getWest(),
      this.getSouth(),
      this.getEast(),
      this.getNorth(),
    ].join(",");
  },
  // 判断两个边界是否相等,maxMargin 表示容差范围
  equals: function (bounds, maxMargin) {
    if (!bounds) {
      return false;
    }

    bounds = toLatLngBounds(bounds);

    return (
      this._southWest.equals(bounds.getSouthWest(), maxMargin) &&
      this._northEast.equals(bounds.getNorthEast(), maxMargin)
    );
  },
  // 判断边界是否有效
  isValid: function () {
    return !!(this._southWest && this._northEast);
  },
};

export function toLatLngBounds(a, b) {
  if (a instanceof LatLngBounds) {
    return a;
  }
  return new LatLngBounds(a, b);
}

使用场景

  1. 地图视口计算
  2. 动态加载数据
  3. 碰撞检测

总结

通过 LatLngBounds 类,Leaflet 提供了高效的地理范围操作工具,支撑了地图的渲染优化、空间查询和交互逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jinuss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值