Search code examples
javascriptleafletopenlayers

Openlayers: creating non-geographical custom tiled map


I am trying to create a map for a web-based game with Openlayers. The game will have three zoom levels with different details. I made one using leaflet but it has a known issue. Now I am trying Opnelayers but I am running into multiple problems.

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Custom Canvas Tiles</title>
    <link rel="stylesheet" href="node_modules/ol/ol.css">
    <style>
      *, body {
        margin: unset;
      }
      .map {
        width: 100%;
        height: 100vh;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
    <script src="https://unpkg.com/[email protected]/dist/elm-pep.js"></script>
    <script type="module" src="main.js"></script>
  </body>
</html>

main.js

import Map from 'ol/Map';
import TileLayer from 'ol/layer/Tile';
import ImageLayer from 'ol/layer/image'
import Static from 'ol/source/ImageStatic';
import View from 'ol/View';
import XYZ from 'ol/source/XYZ';
import Projection from 'ol/proj/Projection';
import { getCenter } from 'ol/extent';

const extentLayer = [0, 0, 1400, 800];
const extentView = [-28000000, -16000000, 28000000, 24000000];
const projectionView = new Projection({
  code: 'pixel-map',
  units: 'pixels',
  extent: extentView,
});

const tileLayer = new TileLayer({
  source: new XYZ({
    url: '/tiles/{z}/{x}/{y}.png',
    wrapX: false,
    tileSize: [280, 400],
    zoom: 0,
    minZoom: 2,
    maxZoom: 4,
  }),
  extentLayer,
});

const view = new View({
  projectionView,
  center: getCenter(extentView),
  zoom: 0,
  minZoom: 2,
  maxZoom: 4,
  extent: extentView
});

const map = new Map({
  target: 'map',
  layers: [
    tileLayer,
  ],
  view
});

Zoom

For some reason, default zoom level starts with 2 even After setting it to 0. I confirmed it by looking at browser network requests. Another problem is that there is a small third zoom.

Extent

My base image is [1400, 800]. I have divided it into 10 tiles(5x2). On each next zoom level a tile is divided into four more detailed tiles (all tiles at any zoom level are [280, 400]). The last two tiles [4, 0] and [4, 1] are not requested by the map. Instead, it tries to load a third row of tiles which I don't even have. I think it must be an issue with the view extent.

I have read the docs multiple times but I am unable to resolve these issues. I tried to follow some examples (there aren't many) to make the view extent the same as the image but it did not work and I ended up with the big values and only they showed the tiles.


Solution

  • You need to specify the projection for the source, and the same extent should be used for tile grid and projection

    const extent = [0, 0, 1400, 800];
    const projection = new Projection({
      code: 'pixel-map',
      units: 'pixels',
      extent,
    });
    
    const tileLayer = new TileLayer({
      source: new XYZ({
        url: '/tiles/{z}/{x}/{y}.png',
        tileSize: [280, 400],
        projection,
        maxZoom: 2,
        maxResolution: 1,
      }),
    });
    
    const view = new View({
      projection,
      center: getCenter(extent),
      zoom: 0,
    });
    
    const map = new Map({
      target: 'map',
      layers: [
        tileLayer,
      ],
      view
    });