Maps4HTML / Web-Map-Custom-Element

A custom <mapml-viewer> and <layer-> element suite
https://maps4html.org/Web-Map-Custom-Element/
Other
54 stars 15 forks source link

dynamically update the layer projection based on map-extents and hence update map-projection if neccessary #912

Open AliyanH opened 9 months ago

AliyanH commented 9 months ago

As pointed by @yhy0217 When removing a map-extent from a single layer in a map, the other map-extents should be used to calculate the projection of the layer.

Relevant to https://github.com/Maps4HTML/Web-Map-Custom-Element/pull/911

We devised an early method (similar to determineLayerProjection, which should be merged to this method) for layer.js to help with this, which is called from map-extent disconnected Callback and can also be called from the layer disconnectedcallback:

// update the layer projection based on it's children, used if map-meta is appended or map-extents are removed
  validateLayerProjection() {
    let meta = this.shadowRoot
      ? this.shadowRoot.querySelector('map-meta[name=projection][content]')
      : this.querySelector('map-meta[name=projection][content]');

    // if map-meta for project exists use it primarily
    if (meta) {
      let metaProjection = M._metaContentToObject(
        meta.getAttribute('content')
      ).content;
      if (
        metaProjection.toUpperCase() !==
        this._layer._properties.projection.toUpperCase()
      ) {
        this._layer._properties.projection = metaProjection.toUpperCase();
      }
    } else {
      // otherwise use map-extents to check if projection can be updated
      let extents = this.shadowRoot
        ? this.shadowRoot.querySelectorAll('map-extent')
        : this.querySelectorAll('map-extent');
      let match = true;
      for (let i = 0; i < extents.length; i++) {
        if (extents[i].units.toUpperCase() !== extents[0].units.toUpperCase()) {
          match = false;
          break;
        }
      }
      // if all map-extents have same projection, update layer projection
      if (match) {
        this._layer._properties.projection = extents[0].units;
      } else {
        // change projection to map-projection, similar to what is done in initialization
        // in determineLayerProjection
        this._layer._properties.projection = this._layer.options.mapprojection;
      }
    }

    // check if only layer for mapml-viewer and to update the map projection if needed
    if (
      this._layer._properties.projection !==
        this._layer.options.mapprojection &&
      this.parentElement.layers.length === 1
    ) {
      this.parentElement.projection = this._layer._properties.projection;
    }
  }

Steps to reproduce, paste the following to https://maps4html.org/web-map-doc/demo/sandbox/ and remove the OSMTILE map-extent, expected outcome should be that the map changes projection to CBMTILE to display the CBMTILE map-extent as it is the only layer in the map:

<mapml-viewer height="700" zoom="15" lon="-75.703611" lat="45.411105" controls projection="OSMTILE">
      <layer- label="Projection changer"  checked>
        <map-extent label="National Geographic" units="OSMTILE" checked >
          <map-input name="TileMatrix" type="zoom" value="18" min="0" max="18"></map-input>
          <map-input name="TileCol" type="location" units="tilematrix" axis="column" min="0" max="262144"></map-input>
          <map-input name="TileRow" type="location" units="tilematrix" axis="row" min="0" max="262144"></map-input>
          <map-link rel="tile" tref="https://server.arcgisonline.com/arcgis/rest/services/NatGeo_World_Map/MapServer/WMTS/tile/1.0.0/NatGeo_World_Map/default/default028mm/{TileMatrix}/{TileRow}/{TileCol}.jpg"></map-link>
        </map-extent>
        <map-extent label="Canada Base Map - Transportation" units="CBMTILE" checked >
          <map-input name="z" type="zoom" min="0" max="18"></map-input>
          <map-input name="y" type="location" units="tilematrix" axis="row"></map-input>
          <map-input name="x" type="location" units="tilematrix" axis="column"></map-input>
          <map-link rel="tile" tref="https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT3978/MapServer/tile/{z}/{y}/{x}?m4h=t" ></map-link>
        </map-extent>    
      </layer->
  </mapml-viewer>