leaflet#TileLayer TypeScript Examples

The following examples show how to use leaflet#TileLayer. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: LoadingControl.ts    From LiveAtlas with Apache License 2.0 6 votes vote down vote up
_layerAdd(e: LeafletEvent) {
		if(!(e.layer instanceof TileLayer)) {
			return;
		}

		try {
			if(e.layer.isLoading()) {
				this.addLoader((e.layer as any)._leaflet_id);
			}

			e.layer.on('loading', this._handleLoading, this);
			e.layer.on('load', this._handleLoad, this);
		} catch (exception) {
			console.warn('L.Control.Loading: Tried and failed to add ' +
				' event handlers to layer', e.layer);
			console.warn('L.Control.Loading: Full details', exception);
		}
	}
Example #2
Source File: LoadingControl.ts    From LiveAtlas with Apache License 2.0 6 votes vote down vote up
_layerRemove(e: LeafletEvent) {
		if(!(e.layer instanceof TileLayer)) {
			return;
		}

		try {
			e.layer.off('loading', this._handleLoading, this);
			e.layer.off('load', this._handleLoad, this);
		} catch (exception) {
			console.warn('L.Control.Loading: Tried and failed to remove ' +
				'event handlers from layer', e.layer);
			console.warn('L.Control.Loading: Full details', exception);
		}
	}
Example #3
Source File: LoadingControl.ts    From LiveAtlas with Apache License 2.0 6 votes vote down vote up
_addLayerListeners(map: Map) {
		// Add listeners for begin and end of load to any layers already
		// on the map
		map.eachLayer((layer: Layer) => {
			if(!(layer instanceof TileLayer)) {
				return;
			}

			if(layer.isLoading()) {
				this.addLoader((layer as any)._leaflet_id);
			}

			layer.on('loading', this._handleLoading, this);
			layer.on('load', this._handleLoad, this);
		});

		// When a layer is added to the map, add listeners for begin and
		// end of load
		map.on('layeradd', this._layerAdd, this);
		map.on('layerremove', this._layerRemove, this);
	}
Example #4
Source File: LoadingControl.ts    From LiveAtlas with Apache License 2.0 6 votes vote down vote up
_removeLayerListeners(map: Map) {
		// Remove listeners for begin and end of load from all layers
		map.eachLayer((layer: Layer) => {
			if(!(layer instanceof TileLayer)) {
				return;
			}

			this.removeLoader((layer as any)._leaflet_id);

			layer.off('loading', this._handleLoading, this);
			layer.off('load', this._handleLoad, this);
		});

		// Remove layeradd/layerremove listener from map
		map.off('layeradd', this._layerAdd, this);
		map.off('layerremove', this._layerRemove, this);
	}
Example #5
Source File: map.component.ts    From mylog14 with GNU General Public License v3.0 6 votes vote down vote up
private createMapOptions(latitude: number, longitude: number) {
    return {
      layers: [
        tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18 })
      ],
      zoom: 15,
      center: latLng(latitude, longitude),
      attributionControl: false,
    };
  }
Example #6
Source File: map.component.ts    From dayz-server-manager with MIT License 6 votes vote down vote up
private createBaseLayers(): void {
        const bounds = this.unproject([this.info!.worldSize, this.info!.worldSize]);
        this.baseLayers = {
            // eslint-disable-next-line @typescript-eslint/naming-convention
            Satelite: tileLayer(
                `${this.mapHost}/${this.mapName}/${this.info!.tilePattern ?? 'tiles/{z}/{x}/{y}.png'}`,
                {
                    attribution: `Leaflet${this.info!.attribution ? `, ${this.info!.attribution}` : ''}`,
                    bounds: [
                        [0, 0],
                        [bounds.lat, bounds.lng],
                    ],
                },
            ),
        };
    }
Example #7
Source File: LiveAtlasTileLayer.ts    From LiveAtlas with Apache License 2.0 4 votes vote down vote up
// noinspection JSUnusedGlobalSymbols
export abstract class LiveAtlasTileLayer extends TileLayer {
	declare options: LiveAtlasTileLayerInternalOptions;
	declare _tiles: LiveAtlasInternalTiles;
	declare _url: string;

	protected readonly tileTemplate: LiveAtlasTileElement;
	protected readonly loadQueue: LiveAtlasTileElement[] = [];
	protected readonly loadingTiles: Set<LiveAtlasTileElement> = Object.seal(new Set());
	protected refreshTimeout?: ReturnType<typeof setTimeout>;

	protected static genericLoadError = new Error('Tile failed to load');

	protected constructor(options: LiveAtlasTileLayerOptions) {
		super('', {
			errorTileUrl: 'images/blank.png',
			zoomReverse: true,
			tileSize: options.tileSize,
			maxNativeZoom: options.nativeZoomLevels,
			minZoom: options.minZoom,
			maxZoom: options.maxZoom || options.nativeZoomLevels + (options.extraZoomLevels || 0),
		});

		Util.setOptions(this, {
			imageFormat: options.imageFormat,
			baseUrl: options.baseUrl,
			tileUpdateInterval: options.tileUpdateInterval,
			nightAndDay: !!options.nightAndDay,
			prefix: options.prefix || '',
			extraZoomLevels: options.extraZoomLevels || 0,
			nativeZoomLevels: options.nativeZoomLevels,
		});

		this.tileTemplate = DomUtil.create('img', 'leaflet-tile') as LiveAtlasTileElement;
		this.tileTemplate.style.width = this.tileTemplate.style.height = this.options.tileSize + 'px';
		this.tileTemplate.alt = '';
		this.tileTemplate.tileName = '';
		this.tileTemplate.callback = falseFn;
		this.tileTemplate.setAttribute('role', 'presentation');

		if(this.options.crossOrigin || this.options.crossOrigin === '') {
			this.tileTemplate.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
		}

		Object.seal(this.tileTemplate);
	}

	// @method createTile(coords: Object, done?: Function): HTMLElement
	// Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
	// to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`
	// callback is called when the tile has been loaded.
	createTile(coords: Coords, done: DoneCallback) {
		const tile = this.tileTemplate.cloneNode(false) as LiveAtlasTileElement;
		this.loadQueue.push(tile);

		tile.onload = () => {
			URL.revokeObjectURL(tile.src); //Revoke the object URL as we don't need it anymore

			this._tileOnLoad(done, tile);
			this.loadingTiles.delete(tile);
			this.tickLoadQueue();
		};

		tile.onerror = () => {
			this._tileOnError(done, tile, LiveAtlasTileLayer.genericLoadError);
			this.loadingTiles.delete(tile);
			this.tickLoadQueue();
		};

		tile.url = this.getTileUrl(coords);
		tile.callback = done;

		this.tickLoadQueue();

		return tile;
	}

	private async fetchTile(tile: LiveAtlasTileElement) {
		if(tile.abortController && !tile.abortController.signal.aborted) {
			tile.abortController.abort();
		}

		tile.abortController = new AbortController();

		try {
			//Retrieve image via a fetch instead of just setting the src
			//This works around the fact that browsers usually don't make a request for an image that was previously loaded,
			//without resorting to changing the URL (which would break caching).
			const response = await fetch(tile.url, {signal: tile.abortController.signal});

			//Call leaflet's error handler if request fails for some reason
			if (!response.ok) {
				this._tileOnError(tile.callback, tile, new Error('Response was not ok'));
				return;
			}

			//Get image data and convert into object URL so it can be used as a src
			//The tile onload listener will take it from here
			const blob = await response.blob();
			tile.src = URL.createObjectURL(blob);
		} catch(e: any) {
			if (e instanceof DOMException && e.name === 'AbortError') {
				return;
			}

			console.error(e);

			this._tileOnError(tile.callback, tile, e);
		}
	}

	protected tickLoadQueue() {
		if (this.loadingTiles.size > 6) {
			return;
		}

		const tile = this.loadQueue.shift();

		if (!tile) {
			return;
		}

		this.loadingTiles.add(tile);
		this.fetchTile(tile);
	}

	refresh() {
		for (const i in this._tiles) {
			if (!Object.prototype.hasOwnProperty.call(this._tiles, i)) {
				continue;
			}

			const tile = this._tiles[i];

			if(tile.loaded) {
				this.loadQueue.push(tile.el);
			}
		}

		this.tickLoadQueue();
	}

	_abortLoading() {
		let tile;

		for (const i in this._tiles) {
			if (!Object.prototype.hasOwnProperty.call(this._tiles, i)) {
				continue;
			}

			tile = this._tiles[i];

			if (tile.coords.z !== this._tileZoom) {
				if (!tile.loaded && tile.el && tile.el.abortController) {
					tile.el.abortController.abort();
				}

				if(this.loadQueue.includes(tile.el)) {
					this.loadQueue.splice(this.loadQueue.indexOf(tile.el), 1);
				}

				this.loadingTiles.delete(tile.el);
			}
		}

		super._abortLoading.call(this);
	}

	_removeTile(key: string) {
		const tile = this._tiles[key];

		if (!tile) {
			return;
		}

		this.loadingTiles.delete(tile.el);

		if(this.loadQueue.includes(tile.el)) {
			this.loadQueue.splice(this.loadQueue.indexOf(tile.el), 1);
		}

		tile.el.onerror = null;
		tile.el.onload = null;

		if(!tile.loaded && tile.el.abortController) {
			tile.el.abortController.abort();
		}

		// @ts-ignore
		super._removeTile(key);
	}

	onAdd(map: LeafletMap): this {
		if(this.options.tileUpdateInterval) {
			this.refreshTimeout = setTimeout(() => this.handlePeriodicRefresh(), this.options.tileUpdateInterval);
		}

		return super.onAdd(map);
	}

	remove() {
		if(this.refreshTimeout) {
			clearTimeout(this.refreshTimeout);
		}

		return super.remove();
	}

	private handlePeriodicRefresh() {
		if(this._map) {
			this.refresh();
		}

		this.refreshTimeout = setTimeout(() => this.handlePeriodicRefresh(), this.options.tileUpdateInterval);
	}
}
Example #8
Source File: rendering.ts    From squadlanes with GNU Affero General Public License v3.0 4 votes vote down vote up
export function resetMap(layerData: LayerData) {
  // remove existing map data
  if (map !== null) {
    map.remove();
    renderInfos = new Map();
    capturePointByCircleMarker = new Map();
    circleMarkerByCapturePoint = new Map();
  }

  const bounds = layerData.background.corners;

  const baseBounds = [
    [bounds[0].y, bounds[0].x],
    [bounds[1].y, bounds[1].x],
  ];
  const width = Math.abs(bounds[0].x - bounds[1].x);
  const height = Math.abs(bounds[0].y - bounds[1].y);

  const up_left_x = Math.min(bounds[0].x, bounds[1].x);
  const up_left_y = Math.min(bounds[0].y, bounds[1].y);

  const zoomOffset = 0;
  let tileSize = 256;

  const x_stretch = tileSize / width;
  const y_stretch = tileSize / height;

  const crs = extend({}, CRS.Simple, {
    // Move origin to upper left corner of map
    // need to do this because TileLayer always puts the left-upper corner on the origin
    transformation: new Transformation(
      x_stretch,
      -up_left_x * x_stretch,
      y_stretch,
      -up_left_y * y_stretch
    ),
  });

  map = leafletMap("map", {
    crs: crs,
    minZoom: 0,
    maxZoom: 6,
    zoomSnap: 0.1,
    zoomDelta: 1.0,
    dragging: true,
    boxZoom: true,
    scrollWheelZoom: true,
    touchZoom: true,
    zoomControl: true,
    doubleClickZoom: false,
    attributionControl: false,
  });

  // @ts-ignore
  map.fitBounds(baseBounds);
  map.createPane("cp");
  map.getPane("cp")!.style.zIndex = "20";
  map.createPane("cpTooltip");
  map.getPane("cpTooltip")!.style.zIndex = "30";
  map.createPane("confirmationLines");
  map.getPane("confirmationLines")!.style.zIndex = "10";
  map.createPane("background");
  map.getPane("background")!.style.zIndex = "0";

  new TileLayer(
    `map-tiles/${layerData.background.minimap_filename}/{z}/{x}/{y}.png`,
    {
      tms: false,
      maxNativeZoom: 4,
      zoomOffset: zoomOffset,
      // scale tiles to match minimap width and height
      tileSize: tileSize,
      pane: "background",
      // @ts-ignore
      bounds: baseBounds,
    }
  ).addTo(map);

  // create markers for capture points
  mapData.capturePoints.forEach((cp) => {
    const cm = circleMarker(cp.pos, {
      radius: 20,
      pane: "cp",
    });

    // remember mapping between CircleMarker and CapturePoint
    circleMarkerByCapturePoint.set(cp, cm);
    capturePointByCircleMarker.set(cm, cp);

    // during mouseover, the font color and size changes
    // (we add a CSS class and re-open the tooltip)
    cm.on("mouseover", (ev) => {
      const tt = cm.getTooltip();
      if (tt !== undefined) {
        // this will probably break at some point
        // @ts-ignore
        DomUtil.addClass(tt._container, "mouseover");
      }
      // re-open tooltip to make sure text is still centered
      cm.closeTooltip();
      cm.openTooltip();
    });
    cm.on("mouseout", (ev) => {
      const tt = cm.getTooltip();
      if (tt !== undefined) {
        // @ts-ignore
        L.DomUtil.removeClass(tt._container, "mouseover");
      }
      cm.closeTooltip();
      cm.openTooltip();
    });
  });

  // make sure the leaflet map rescales properly when the window is resized
  const mapDiv = document.getElementById("map")!;
  new ResizeObserver(() => {
    map!.invalidateSize();
    // @ts-ignore
    map!.fitBounds(baseBounds, {
      animate: false,
    });
  }).observe(mapDiv);

  // Debug
  if (window.location.hostname.startsWith("dev.")) {
    map.addEventListener("mousedown", function (ev) {
      // @ts-ignore
      const lat = ev.latlng.lat;
      // @ts-ignore
      const lng = ev.latlng.lng;
    });
  }
}