BIGEMPA Js API示例中心

KML纠偏源代码展示

代码编辑区 运行 下载 还原
<!DOCTYPE html>
<html>

<head>
  <meta charset='UTF-8' />
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
  <!--
        以下CSS地址请在安装软件了替换成本地的地址
        CSS地址请使用:
        http://localhost:9000/bigemap.js/v2.1.0/bigemap.css
        软件下载地址 http://www.bigemap.com/reader/download/detail201802017.html
    -->
  <link href='http://www.bigemap.com:9000/bigemap.js/v2.1.0/bigemap.css' rel='stylesheet' />
  <link href="https://cdn.bootcss.com/Buttons/2.0.0/css/buttons.min.css" rel="stylesheet">
  <!--
        JS地址请使用:
        http://localhost:9000/bigemap.js/v2.1.0/bigemap.js
    -->
  <script src='http://www.bigemap.com:9000/bigemap.js/v2.1.0/bigemap.js'></script>
  <!--
        引入加载KML的JS插件
    -->
  <script type="text/javascript" src="http://www.bigemap.com/mapoffline/js/togeojson.js"></script>
  <!-- 引入Geojson转换KML的js插件 -->
  <script src="http://demo.bigemap.com/static/map/js/tokml.js"></script>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }

    .tool {
      position: absolute;
      z-index: 10;
      right: 10px;
      top: 60px;
    }

    .info {
      position: fixed;
      top: 40px;
      color: #8a6d3b;
      z-index: 99;
      margin: 0;
      background-color: #fcf8e3;
      border-color: #faebcc;
      left: 0;
      right: 0;
      text-align: center;
    }

    #ceng {
      position: absolute;
      top: 120px;
      left: 0;
      z-index: 10;

    }

  #ceng::before{
    content: '当前地图源:';
    position: absolute;
    left:0;
    right: 0;
    bottom: -10px;
    padding: 5px 10px;
    top: -40px;
    background-color: #369;
    border-radius: 5px;
    font-size: 14px;
    color: #fff;
    z-index: -1;
  }
    #checkExport {
      display: none;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      width: 600px;
      height: 400px;
      background-color: skyblue;
      border: slategrey 1px solid;
      z-index: 10000;
      padding: 10px 0 0 10px;
    }

    #checkExport>div {
      padding: 10px;
      outline: turquoise 1px solid;
    }

    #checkExport>button{
      position: absolute;
      right: 0;
      top:0;
      padding: 5px 5px 0 0;
    }
  </style>
  <title>切换图层</title>
</head>

<body>
  <p class="info">
    数据保存在本地,刷新会消失,仅仅用作测试,左侧仅供纠偏效果展示使用,切换会清楚当前覆盖物
  </p>
  <p class="tool">
    <a id="satellite" class="button button-tiny button-rounded button-primary" href="javascript:void (0);">导入KML</a>
    <a id="export" class="button button-tiny button-rounded button-primary" href="javascript:void (0);">导出</a>
    <input type="file" accept=".kml" style="display: none" id="upload">
  </p>
  <div id="ceng">
    <a href="javascript:void(0)" data-type="arcgis-satellite" data-map="arcgis" class="button button-tiny button-rounded">arcgis(wgs 84)</a>
    <a href="javascript:void(0)" data-type="baidu-map" data-map="baidu" class="button button-tiny button-rounded">百度(bd09)</a>
    <a href="javascript:void(0)" data-type="amap-map"  data-map="amap" class="button button-tiny button-rounded button-primary">高德(gcj02)</a>
  </div>
  <div id="checkExport">
    <div>
      <span>导入数据坐标系</span>
      <select name="" id="from">
        <option value="">请选择</option>
        <option value="WGS84">WGS84(无偏移)</option>
        <option value="Cj-02">火星坐标系(Cj-02)</option>
        <option value="BD-09">百度坐标系(BD-09)</option>
      </select>
    </div>
    <div>
      <span>导出数据源</span>
      <select name="" id="to" autofocus>
        <option value="">请选择</option>
        <option value="WGS84">WGS84(无偏移)</option>
        <option value="Cj-02">火星坐标系(Cj-02)</option>
        <option value="BD-09">百度坐标系(BD-09)</option>
      </select>
    </div>
    <div>
      <span>导出格式</span>
      <select name="" id="form" autofocus>
        <option value="">请选择</option>
        <option value="geoJSON">geoJSON</option>
        <option value="kml">kml</option>
      </select>
    </div>
    <a href="javascript:void(0)" class="button button-tiny button-rounded button-primary"
      download="javascript:void(0)">确认导出</a>
    <button>x</button>
  </div>
  <a download="" style="display: none;" id="download"></a>
  <div id='map'></div>
  <script src="http://www.bigemap.com/Public/common/js/jquery.min.js"></script>
  <script src="http://demo.bigemap.com/static/map/js/tokml.js"></script>
  <script type="text/javascript">
    // 软件配置信息地址,软件安装完成之后使用本地地址,如:http://localhost:9000
    BM.Config.HTTP_URL = 'http://www.bigemap.com:9000';
    // 在ID为map的元素中实例化一个地图,并设置地图的ID号为 bigemap.baidu-map,ID号程序自动生成,无需手动配置,并设置地图的投影为百度地图 ,中心点,默认的级别和显示级别控件
    var map = BM.map('map', 'bigemap.amap-map', {
      center: [30.66, 104.001],
      zoom: 15,
      zoomControl: true,
      attributionControl: false,
      preferCanvas: true, //适用于数据量大时 地图反应速度加快
    });
    var btns = document.querySelectorAll('#ceng a');
    $('#ceng').on('click','a',function (){
      $('#ceng a').removeClass('button-primary');
      $(this).addClass('button-primary');
      var type=$(this).data('map');
      var crs=type==='baidu'?BM.CRS.Baidu:BM.CRS.EPSG3857;
      geo&&geo.remove(),geo = null;
      map.remove();
      map = BM.map('map', 'bigemap.{id}'.replace('{id}',$(this).data('type')), {
        crs,
        center: [30.66, 104.001],
        zoom: 15,
        preferCanvas: true,
        zoomControl: true
      });

      if (cacheData){
         geo = BM.geoJSON(cacheData, {
           style: function (feature) {}
         }).bindPopup(function (layer) {
           return `<div><h4>${layer.feature.properties.name}</h4>
             <p>${layer.feature.properties.description}</p></div>`
         }).addTo(map);
        map.fitBounds(geo.getBounds());
      }
    });
    var blob, href, geo,cacheData;
    var bdcj = {
        features: [],
        type: "FeatureCollection"
      },
      cjbd = {
        features: [],
        type: "FeatureCollection"
      };
    $('#upload').on('change', function () {
      var file = this.files[0];
      var extension = file.name.split('.');
      extension = extension.pop();
      if (extension !== 'kml') {
        alert('只能是KML格式');
        return;
      }
      var reader = new FileReader();
      reader.readAsText(file);
      reader.onload = function () {
        var dom = (new DOMParser()).parseFromString(this.result, 'text/xml');
        var geojsonFeature = toGeoJSON.kml(dom);
        cacheData=geojsonFeature;
        geo&&geo.remove();
        geo = BM.geoJSON(geojsonFeature, {
          style: function (feature) {}
        }).bindPopup(function (layer) {
          return `<div><h4>${layer.feature.properties.name}</h4>
            <p>${layer.feature.properties.description}</p></div>`
        }).addTo(map);
        map.fitBounds(geo.getBounds());
      }
    });
    $('#satellite').on('click', function () { //显示上传
      $('#upload').click();
    });
    $('#export').click(function () {
      $('#checkExport').show();
    })
    $('#checkExport>button').click(function () {
      $('#from').val('');$('#to').val('');$('#form').val('');
      $('#checkExport').hide();
    })
    $('#checkExport>a').click(function () {
      let from = $('#from').val();
      let to = $('#to').val();
      let form = $('#form').val();
      if (from && to && form) {
        if (transLatLng(from, to, form))$('#checkExport>button').click();
      } else {
        console.error(253);
      }
    })

    //定义转换方法
    function transLatLng(from, to, form) {
      let temp = {
        features: [],
        type: "FeatureCollection"
      }
      if (form == to) {
        geo.eachLayer(function (item) {
          temp.features.push(item.feature);
        })
      } else {
        if (from == 'WGS84') {
          if (to == 'Cj-02') {
            let fn = wgs84togcj02;
            let fn1 = checkType(geo); //判断类型拿到方法
            geo.eachLayer(function (item) {
              let obj = fn1(item, fn);
              temp.features.push(obj);
            });
          } else {
            let fn = wgs84togcj02;
            let fn2 = gcj02tobd09;
            let fn1 = checkType(geo); //判断类型拿到方法
            geo.eachLayer(function (item) {
              let obj = fn1(item, fn, fn2);
              temp.features.push(obj);
            });
          }
        } else if (from == 'Cj-02') {
          if (to == 'WGS84') {
            let fn = gcj02towgs84;
            let fn1 = checkType(geo); //判断类型拿到方法
            geo.eachLayer(function (item) {
              let obj = fn1(item, fn);
              temp.features.push(obj);
            });
          } else {
            let fn = gcj02tobd09;
            let fn1 = checkType(geo); //判断类型拿到方法
            geo.eachLayer(function (item) {
              let obj = fn1(item, fn);
              temp.features.push(obj);
            });
          }
        } else {
          if (to == 'WGS84') {
            let fn = bd09togcj02;
            let fn2 = gcj02towgs84;
            let fn1 = checkType(geo); //判断类型拿到方法
            geo.eachLayer(function (item) {
              let obj = fn1(item, fn, fn2);
              temp.features.push(obj);
            });
          } else {
            let fn = bd09togcj02;
            let fn1 = checkType(geo); //判断类型拿到方法
            geo.eachLayer(function (item) {
              let obj = fn1(item, fn);
              temp.features.push(obj);
            });
          }
        }
      }
      if (form == 'kml') {
        var blob = new Blob([tokml(geo.toGeoJSON())]);
        var href = URL.createObjectURL(blob);
        $('#download').prop('href', href);
        $('#download').prop('download', 'kml.kml');
        document.querySelector('#download').click();
        return true
      } else {
        var blob = new Blob([JSON.stringify(temp)]);
        var href = URL.createObjectURL(blob);
        $('#download').prop('href', href);
        $('#download').prop('download', 'geojson.geojson');
        document.querySelector('#download').click();
        return true
      }
    }

    function checkType(geo) {
      switch (Object.values(geo._layers)[0].feature.geometry.type) {
        case 'Point':
        case 'circle':
        case 'circleMarker': //判断类型,若为单点使用getLatLng,若为点组则应使用getLatLngs
          return function (item, fn, fn2) { //单函数为一次转换,双函数为二次转换,且顺序为先后
            const lat = item.getLatLng().lat;
            const lng = item.getLatLng().lng;
            let latlng_ts;
            fn2 ? latlng_ts = fn2(fn(lat, lng)) : latlng_ts = fn(lat, lng);
            let obj = { //保存位置描述,类型等信息
              geometry: {
                coordinates: latlng_ts,
                type: item.feature.geometry.type
              },
              properties: item.feature.properties
            }
            item.setLatLng(latlng_ts);
            return obj;
          }
          break;
        default:
          return function (item, fn, fn2) { //单函数为一次转换,双函数为二次转换,且顺序为先后
            const latlngs = item.getLatLngs()[0];
            let latlng_ts=[];//数组存放纠偏后的经纬对
            for (let i = 0; i < latlngs.length; i++) {
              console.log(latlngs[i]);
              const {lat,lng}=latlngs[i];
              console.log(lat,lng,latlngs[i]);
              let temp_latlng;
              fn2 ?temp_latlng= fn2(fn(lat, lng)): temp_latlng = fn(lat, lng);
              console.log(temp_latlng);
              latlng_ts.push(temp_latlng);
            }
            let obj = { //保存位置描述,类型等信息
              geometry: {
                coordinates: latlng_ts,
                type: item.feature.geometry.type
              },
              properties: item.feature.properties
            }
            console.log(latlng_ts);
            item.setLatLngs(latlng_ts);
            return obj;
          }
      }
    }
      //定义一些常量用于算法纠偏
      var x_PI = 3.14159265358979324 * 3000.0 / 180.0;
      var PI = 3.1415926535897932384626;
      var a = 6378245.0;
      var ee = 0.00669342162296594323;

      /**
       * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
       * 即 百度 转 谷歌、高德
       */
      function bd09togcj02(bd_lat, bd_lon) {
        var x_pi = 3.14159265358979324 * 3000.0 / 180.0;
        var x = bd_lon - 0.0065;
        var y = bd_lat - 0.006;
        var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
        var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
        var gg_lng = z * Math.cos(theta);
        var gg_lat = z * Math.sin(theta);
        return [gg_lat, gg_lng]
      }

      /**
       * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
       * 即谷歌、高德 转 百度
       */
      function gcj02tobd09(lat, lng) {
        var z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
        var theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
        var bd_lng = z * Math.cos(theta) + 0.0065;
        var bd_lat = z * Math.sin(theta) + 0.006;
        return [bd_lat, bd_lng]
      }

      /**
       * WGS84转GCj02
       */
      function wgs84togcj02(lat, lng) {
        if (out_of_china(lng, lat)) {
          return [lat, lng]
        } else {
          var dlat = transformlat(lng - 105.0, lat - 35.0);
          var dlng = transformlng(lng - 105.0, lat - 35.0);
          var radlat = lat / 180.0 * PI;
          var magic = Math.sin(radlat);
          magic = 1 - ee * magic * magic;
          var sqrtmagic = Math.sqrt(magic);
          dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
          dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
          var mglat = lat + dlat;
          var mglng = lng + dlng;
          return [mglat, mglng]
        }
      }

      /**
       * GCJ02 转换为 WGS84
       */
      function gcj02towgs84(lat, lng) {
        if (out_of_china(lng, lat)) {
          return [lat, lng]
        } else {
          var dlat = transformlat(lng - 105.0, lat - 35.0);
          var dlng = transformlng(lng - 105.0, lat - 35.0);
          var radlat = lat / 180.0 * PI;
          var magic = Math.sin(radlat);
          magic = 1 - ee * magic * magic;
          var sqrtmagic = Math.sqrt(magic);
          dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
          dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
          mglat = lat + dlat;
          mglng = lng + dlng;
          return [lat * 2 - mglat, lng * 2 - mglng]
        }
      }

      function transformlat(lng, lat) {
        var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
        return ret
      }

      function transformlng(lng, lat) {
        var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
        return ret
      }

      /**
       * 判断是否在国内,不在国内则不做偏移
       */
      function out_of_china(lng, lat) {
        return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false);
      }
  </script>
</body>

</html>