/** * @module ol/source/TileDebug */ import {createCanvasContext2D} from '../dom.js'; import EventType from '../events/EventType.js'; import {get as getProjection} from '../proj.js'; import {toSize} from '../size.js'; import {renderXYZTemplate} from '../uri.js'; import DataTile from './DataTile.js'; import ImageTile from './ImageTile.js'; /** * @typedef {Object} Options * @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Optional projection. * @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid. * @property {boolean} [wrapX=true] Whether to wrap the world horizontally. * @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] * Set to `1` when debugging `VectorTile` sources with a default configuration. * Choose whether to use tiles with a higher or lower zoom level when between integer * zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}. * @property {import("./Tile.js").default} [source] Tile source. * This allows `projection`, `tileGrid`, `wrapX` and `zDirection` to be copied from another source. * If both `source` and individual options are specified the individual options will have precedence. * @property {string} [template='z:{z} x:{x} y:{y}'] Template for labeling the tiles. * Should include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders. * @property {string} [color='grey'] CSS color to fill text and stroke grid lines of each tile. */ /** * @classdesc * A pseudo tile source, which does not fetch tiles from a server, but renders * a grid outline for the tile grid/projection along with the coordinates for * each tile. See examples/canvas-tiles for an example. * @api */ class TileDebug extends ImageTile { /** * @param {Options} [options] Debug tile options. */ constructor(options) { /** * @type {Options} */ options = options || {}; const template = options.template || 'z:{z} x:{x} y:{y}'; const source = options.source; const color = options.color || 'grey'; super({ transition: 0, wrapX: options.wrapX !== undefined ? options.wrapX : source !== undefined ? source.getWrapX() : undefined, }); const setReady = () => { this.projection = options.projection !== undefined ? getProjection(options.projection) : source !== undefined ? source.getProjection() : this.projection; this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : source !== undefined ? source.getTileGrid() : this.tileGrid; this.zDirection = options.zDirection !== undefined ? options.zDirection : source !== undefined ? source.zDirection : this.zDirection; if (source instanceof DataTile) { this.transformMatrix = source.transformMatrix?.slice() || null; } const tileGrid = this.tileGrid; if (tileGrid) { this.setTileSizes( tileGrid .getResolutions() .map((r, i) => toSize(tileGrid.getTileSize(i)).map((s) => Math.max(Math.floor(s), 1), ), ), ); } this.setLoader((z, x, y, loaderOptions) => { const text = renderXYZTemplate(template, z, x, y, loaderOptions.maxY); const [width, height] = this.getTileSize(z); const context = createCanvasContext2D(width, height); context.strokeStyle = color; context.strokeRect(0.5, 0.5, width + 0.5, height + 0.5); context.fillStyle = color; context.strokeStyle = 'white'; context.textAlign = 'center'; context.textBaseline = 'middle'; context.font = '24px sans-serif'; context.lineWidth = 4; context.strokeText(text, width / 2, height / 2, width); context.fillText(text, width / 2, height / 2, width); // make the loader aysnc, so it behaves like other sources that fetch data from a remote server return Promise.resolve(context.canvas); }); this.setState('ready'); }; if (source === undefined || source.getState() === 'ready') { setReady(); } else { const handler = () => { if (source.getState() === 'ready') { source.removeEventListener(EventType.CHANGE, handler); setReady(); } }; source.addEventListener(EventType.CHANGE, handler); } } } export default TileDebug;