gmap.pt 10.2 KB
<span tal:define="name name|field.name;
    css_class css_class|field.widget.css_class;
    oid oid|field.oid;
    style style|field.widget.style;
    map_zoom map_zoom|field.widget.map_zoom;
    map_center map_center|field.widget.map_center;
    gmap_key gmap_key|field.widget.gmap_key;
    gmap_height gmap_height|field.widget.gmap_height;
    gmap_width gmap_width|field.widget.gmap_width;
    gmap_control gmap_control|field.widget.gmap_control;
    html_info html_info|field.widget.html_info;
    gmap_data_style gmap_data_style|field.widget.gmap_data_style;
    gmap_edit_url gmap_edit_url|field.widget.gmap_edit_url;
    "
     tal:omit-tag="">
  <textarea id="${oid}" name="${name}" style="display:none;" readonly
       tal:attributes="class string: form-control ${css_class or ''};
      style style;
      attributes|field.widget.attributes|{};">${cstruct}</textarea>

  <div id="gmap" class="gmap"></div>

  <style>
    .gmap {
      height: ${gmap_height};
      width: ${gmap_width};
    }
  </style>

  <script type="text/javascript">
    let map_zoom = ${map_zoom};
    let map_center = ${map_center};
    let map;
    let btnCurrent = {lat: 0, lng: 0};
    let selectedFeature = null;
    let btnRemove;
    let geom = document.getElementById('${oid}');
    let infoWindow;
    let feature_data = {};
    let contents = ${html_info};
    let edit_url = "${gmap_edit_url}";


    function initMap() {
      map = new google.maps.Map(document.getElementById("gmap"), {
        center: {lat: map_center[0], lng: map_center[1]},
        zoom: map_zoom,
        animation: google.maps.Animation.DROP,
        streetViewControl: false,
        mapTypeId: "satellite",
        mapTypeControlOptions: {
          style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
        },
      });
      map.data.setStyle(${structure: gmap_data_style});
      infoWindow = new google.maps.InfoWindow({
        content: "",
        ariaLabel: "Uluru",
      });

      map.data.setControls(${gmap_control});

      // google.maps.event.addListener(map, 'zoom_changed', function () {
      //   let zoomLevel = map.getZoom();
      //   if (zoomLevel < 11) {
      //     map.data.forEach(function (e) {
      //       let bounds = new google.maps.LatLngBounds();
      //       bounds = extendBound(bounds, e);
      //       map.data.add({
      //         geometry: new google.maps.Data.Point(bounds.getCenter()),
      //       });
      //     });
      //   }
      // });
      google.maps.event.addListener(map.data, 'addfeature', function (e) {
        if (map.data.getDrawingMode() !== null) {
          let bounds = new google.maps.LatLngBounds();
          bounds = extendBound(bounds, e.feature);
          map.fitBounds(bounds);
        }
      });

      google.maps.event.addListener(map.data, 'click', function (e) {
        if (e.hasOwnProperty("feature") === true) {
          selectedFeature = e.feature;
          btnRemove.disabled = false;
          if (e.feature.getGeometry().getType() === "Point") {
            map.setCenter(e.feature.getGeometry().get());
            map.setZoom(18);
          }
          showInfo(e);
        } else {
          selectedFeature = null;
          btnRemove.disabled = true;
        }
      });

      loadData();
      addYourLocationButton();
      bindDataLayerListeners(map.data);
    }

    function loadData() {
      if (geom.value === "") return;
      let data = JSON.parse(geom.value);
      if (data !== undefined) {
        map.data.forEach(function (f) {
          map.data.remove(f);
        });
        map.data.addGeoJson(data);
      }
      setControls();
    }

    function showInfo(event) {
      if (contents.length<1) return;
      infoWindow.setPosition(event.latLng);
      let content = "";
      for (let key in contents) {
        let keys = contents[key];
        let value = key === "id" ? event.feature.getId() : event.feature.getProperty(key);
        value = value === undefined ? "" : value
        let cnt = keys[0] + ": " + value;
        if (keys.length > 1) {
          if (keys[1] === 'b') {
            cnt = "<b>" + cnt + "</b>"
          }
        }
        content += cnt + '<br>';
      }
      if (edit_url !== "" && event.feature.getId() !== undefined) {
        let url = edit_url.replace("{id}", selectedFeature.getId());
        content += '<a class="btn btn-info" href="{url}">Edit</a>'.replace("{url}", url);
      }
      infoWindow.setContent(content);
      infoWindow.open(map);
    }


    function bindDataLayerListeners(dataLayer) {
      dataLayer.addListener('addfeature', saveData);
      dataLayer.addListener('removefeature', saveData);
      dataLayer.addListener('setgeometry', saveData);
    }

    function extendBound(bounds, feature) {
      if (feature === undefined) return bounds;
      let featureType = feature.getGeometry().getType();
      if (featureType === 'LineString') {
        feature.getGeometry().getArray().forEach(function (latLng) {
          bounds.extend(latLng);
        });
      } else if (featureType === 'Polygon') {
        feature.getGeometry().getArray().forEach(function (path) {
          path.getArray().forEach(function (latLng) {
            bounds.extend(latLng);
          });
        });
      }
      return bounds;
    }

    function setControls() {
      let total = 0;
      let bounds = new google.maps.LatLngBounds();
      map.data.forEach(function (e) {
        total++;
        bounds = extendBound(bounds, e);
      });
      if (total > 0) {
        map.fitBounds(bounds);
        map.data.setDrawingMode(null);
        map.data.setControls(null);
        let zoomLevel = map.getZoom();
        if (total > 1) {
          map.data.forEach(function (e) {
            let bounds = new google.maps.LatLngBounds();
            bounds = extendBound(bounds, e);
            let properties = {};
            e.forEachProperty(
                function (val, key) {
                  properties[key] = val;
                }
            );
            map.data.add({
              geometry: new google.maps.Data.Point(bounds.getCenter()),
              properties: properties,
              // id:e.getId()
            });
          });
        }
      } else {
        map.data.setControls(${gmap_control});
      }
    }

    function saveData() {
      map.data.toGeoJson(function (json) {
        geom.value = JSON.stringify(json);
      });
      setControls();
    }

    function addYourLocationButton() {
      let controlDiv = document.createElement('div');
      let btnCurrent = document.createElement('button');
      btnCurrent.type = "button";
      btnCurrent.style.backgroundColor = '#fff';
      btnCurrent.style.border = 'none';
      btnCurrent.style.outline = 'none';
      btnCurrent.style.width = '28px';
      btnCurrent.style.height = '28px';
      btnCurrent.style.borderRadius = '2px';
      btnCurrent.style.boxShadow = '0 1px 4px rgba(0,0,0,0.3)';
      btnCurrent.style.cursor = 'pointer';
      btnCurrent.style.marginRight = '10px';
      btnCurrent.style.padding = '0';
      btnCurrent.title = 'Your Location';
      controlDiv.appendChild(btnCurrent);

      let imgCurrent = document.createElement('div');
      imgCurrent.style.margin = '5px';
      imgCurrent.style.width = '18px';
      imgCurrent.style.height = '18px';
      imgCurrent.style.backgroundImage = 'url(https://maps.gstatic.com/tactile/mylocation/mylocation-sprite-2x.png)';
      imgCurrent.style.backgroundSize = '180px 18px';
      imgCurrent.style.backgroundPosition = '0 0';
      imgCurrent.style.backgroundRepeat = 'no-repeat';
      btnCurrent.appendChild(imgCurrent);
      let txtCurrent = document.createElement('i');
      txtCurrent.className = "fa";
      txtCurrent.ariaHidden = "true"; //<i class="fa fa-trash" aria-hidden="true"></i>
      imgCurrent.appendChild(txtCurrent);

      google.maps.event.addListener(map, 'center_changed', function () {
        imgCurrent.style['background-position'] = '0 0';
      });

      btnCurrent.addEventListener('click', function () {
        let imgX = 0,
            animationInterval = setInterval(function () {
              imgX = -imgX - 18;
              imgCurrent.style['background-position'] = imgX + 'px 0';
            }, 500);

        if (navigator.geolocation) {
          navigator.geolocation.getCurrentPosition(function (position) {
            let latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
            map.setCenter(latlng);
            clearInterval(animationInterval);
            secondChild.style['background-position'] = '-144px 0';
          });
        } else {
          clearInterval(animationInterval);
          btnCurrent.style['background-position'] = '0 0';
        }
      });


      // let btnRemove = document.getElementById('btnRemove');
      btnRemove = document.createElement('button');
      btnRemove.type = "button";
      btnRemove.style.backgroundColor = '#fff';
      btnRemove.style.border = 'none';
      btnRemove.style.outline = 'none';
      btnRemove.style.width = '28px';
      btnRemove.style.height = '28px';
      btnRemove.style.borderRadius = '2px';
      btnRemove.style.boxShadow = '0 1px 4px rgba(0,0,0,0.3)';
      btnRemove.style.cursor = 'pointer';
      // btnRemove.style.marginRight = '10px';
      btnRemove.style.padding = '0';
      btnRemove.title = 'Delete Selected Feature';
      controlDiv.appendChild(btnRemove);
      let imgRemove = document.createElement('div');
      imgRemove.style.margin = '5px';
      imgRemove.style.width = '18px';
      imgRemove.style.height = '18px';
      btnRemove.appendChild(imgRemove);
      let txtRemove = document.createElement('i');
      txtRemove.className = "fa fa-trash";
      txtRemove.ariaHidden = "true"; //<i class="fa fa-trash" aria-hidden="true"></i>
      imgRemove.appendChild(txtRemove);

      btnRemove.addEventListener("click", function () {
        if (selectedFeature !== null) {
          map.data.remove(selectedFeature);
          selectedFeature = null;
          btnRemove.disabled = true;
          saveData();
        }
      });

      controlDiv.index = 1;
      map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(controlDiv);
    }

  </script>

  <script async defer
          src="https://maps.googleapis.com/maps/api/js?v=3&key=${gmap_key}&libraries=drawing&callback=initMap">
  </script>
</span>