Skip to content

Commit

Permalink
Refactoring of the @qgis-js/ol package and extentBuffer for XYZ tile …
Browse files Browse the repository at this point in the history
…rendering (#13)
  • Loading branch information
boardend committed Nov 9, 2023
1 parent fa17683 commit 2e8b293
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 149 deletions.
52 changes: 40 additions & 12 deletions packages/qgis-js-ol/src/QgisCanvasDataSource.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import type { QgisApi } from "qgis-js";

import ImageSource, { Options } from "ol/source/Image";
import { getWidth, getHeight } from "ol/extent";

/**
* @internal
*/
export interface QgisCanvasDataSourceOptions extends Options {
renderFunction?: QgisCanvasRenderFunction;
}

export type QgisCanvasRenderFunction = (
api: QgisApi,
srid: string,
xMin: number,
yMin: number,
Expand All @@ -15,15 +19,36 @@ export type QgisCanvasRenderFunction = (
pixelRatio: number,
) => Promise<ImageData>;

export interface QgisCanvasDataSourceOptions extends Options {}

export class QgisCanvasDataSource extends ImageSource {
protected renderFunction: QgisCanvasRenderFunction;
protected api: QgisApi;

protected static DEFAULT_RENDERFUNCTION: QgisCanvasRenderFunction = (
api: QgisApi,
srid: string,
xMin: number,
yMin: number,
xMax: number,
yMax: number,
width: number,
height: number,
pixelRatio: number,
) => {
return api.renderImage(
srid,
new api.Rectangle(xMin, yMin, xMax, yMax),
width,
height,
pixelRatio,
);
};

protected renderFunction: QgisCanvasRenderFunction | undefined;

protected getrenderFunction(): QgisCanvasRenderFunction {
return this.renderFunction || QgisCanvasDataSource.DEFAULT_RENDERFUNCTION;
}

constructor(
renderFunction: QgisCanvasRenderFunction,
options: QgisCanvasDataSourceOptions = {},
) {
constructor(api: QgisApi, options: QgisCanvasDataSourceOptions = {}) {
super({
loader: (extent, resolution, requestPixelRatio) => {
return new Promise(async (resolve) => {
Expand All @@ -33,7 +58,9 @@ export class QgisCanvasDataSource extends ImageSource {
const width = Math.round(getWidth(extent) / imageResolution);
const height = Math.round(getHeight(extent) / imageResolution);

const imageData = await this.renderFunction(
const renderFunction = this.getrenderFunction();
const imageData = await renderFunction(
this.api,
this.getProjection()?.getCode() || "EPSG:3857",
extent[0],
extent[1],
Expand All @@ -50,6 +77,7 @@ export class QgisCanvasDataSource extends ImageSource {
...options,
});

this.renderFunction = renderFunction;
this.api = api;
this.renderFunction = options.renderFunction;
}
}
71 changes: 55 additions & 16 deletions packages/qgis-js-ol/src/QgisXYZDataSource.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { QgisApi } from "qgis-js";

import XYZ, { Options } from "ol/source/XYZ";

import { createCanvasContext2D } from "ol/dom";
Expand All @@ -6,26 +8,57 @@ import { toSize } from "ol/size";
import type { TileCoord } from "ol/tilecoord";
import ImageTile from "ol/ImageTile";

export interface QgisXYZDataSourceOptions extends Options {
extentBufferFactor?: number | (() => number);
renderFunction?: QgisXYZRenderFunction;
debug?: boolean;
}

export type QgisXYZRenderFunction = (
api: QgisApi,
tileCoord: TileCoord,
tileSize: number,
pixelRatio: number,
extentBufferFactor: number,
) => Promise<ImageData>;

export interface QgisXYZDataSourceOptions extends Options {
debug?: boolean;
}

export class QgisXYZDataSource extends XYZ {
/**
* @internal
*/
protected renderFunction: QgisXYZRenderFunction;

constructor(
renderFunction: QgisXYZRenderFunction,
options: QgisXYZDataSourceOptions = {},
) {
protected api: QgisApi;

protected static DEFAULT_RENDERFUNCTION: QgisXYZRenderFunction = (
api: QgisApi,
tileCoord: TileCoord,
tileSize: number,
devicePixelRatio: number,
extentBufferFactor: number,
) => {
return api.renderXYZTile(
tileCoord[1],
tileCoord[2],
tileCoord[0],
tileSize,
devicePixelRatio,
extentBufferFactor,
);
};

protected renderFunction: QgisXYZRenderFunction | undefined;

protected getrenderFunction(): QgisXYZRenderFunction {
return this.renderFunction || QgisXYZDataSource.DEFAULT_RENDERFUNCTION;
}

protected static DEFAULT_EXTENTBUFFERFACTOR = 0;

protected extentBufferFactor: number | number | (() => number) | undefined;

protected getextentBufferFactor(): number {
return typeof this.extentBufferFactor === "function"
? this.extentBufferFactor()
: this.extentBufferFactor || QgisXYZDataSource.DEFAULT_EXTENTBUFFERFACTOR;
}

constructor(api: QgisApi, options: QgisXYZDataSourceOptions = {}) {
super({
tileUrlFunction: (tileCoord, pixelRatio) => {
const tileSize = (
Expand All @@ -34,18 +67,22 @@ export class QgisXYZDataSource extends XYZ {
return `${tileSize * (pixelRatio || 1)}`;
},
tileLoadFunction: async (tile, text) => {
if (this.tileGrid && this.renderFunction) {
const renderFunction = this.getrenderFunction();
if (this.tileGrid && renderFunction) {
console.assert(tile instanceof ImageTile);
const imageTile = tile as ImageTile;

const tileSize = parseInt(text);
const pixelRatio = Math.round(tileSize / 256);

const context = createCanvasContext2D(tileSize, tileSize);
const imageData = await this.renderFunction(

const imageData = await renderFunction(
this.api,
tile.getTileCoord(),
tileSize,
pixelRatio,
this.getextentBufferFactor(),
);
context.putImageData(imageData, 0, 0);

Expand All @@ -69,6 +106,8 @@ export class QgisXYZDataSource extends XYZ {
...options,
});

this.renderFunction = renderFunction;
this.api = api;
this.renderFunction = options.renderFunction;
this.extentBufferFactor = options.extentBufferFactor;
}
}
69 changes: 2 additions & 67 deletions packages/qgis-js-ol/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,67 +1,2 @@
import type { QgisApi } from "qgis-js";

import {
QgisXYZDataSource,
QgisXYZDataSourceOptions,
} from "./QgisXYZDataSource";

export type { QgisXYZDataSource };

import {
QgisCanvasDataSource,
QgisCanvasDataSourceOptions,
} from "./QgisCanvasDataSource";
import type { TileCoord } from "ol/tilecoord";

export type { QgisCanvasDataSource };

export type Mode = "xyz" | "canvas";

export class QgisOpenLayers {
QgisXYZDataSource(api: QgisApi, options?: QgisXYZDataSourceOptions) {
return new QgisXYZDataSource(
(tileCoord: TileCoord, tileSize: number, devicePixelRatio: number) => {
return api.renderXYZTile(
tileCoord[1],
tileCoord[2],
tileCoord[0],
tileSize,
devicePixelRatio,
);
},
{
...(options ? options : {}),
},
);
}
QgisCanvasDataSource(api: QgisApi, options?: QgisCanvasDataSourceOptions) {
return new QgisCanvasDataSource(
(
srid: string,
xMin: number,
yMin: number,
xMax: number,
yMax: number,
width: number,
height: number,
pixelRatio: number,
) => {
return api.renderImage(
srid,
new api.Rectangle(xMin, yMin, xMax, yMax),
width,
height,
pixelRatio,
);
},
{
...options,
...{
//TODO: make this work with the projection of the QGIS project
//projection: "EPSG:3857",
//projection: api.srid()
},
},
);
}
}
export { QgisXYZDataSource } from "./QgisXYZDataSource";
export { QgisCanvasDataSource } from "./QgisCanvasDataSource";
21 changes: 15 additions & 6 deletions packages/qgis-js/src/QgisApiAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,25 @@ export class QgisApiAdapterImplementation implements QgisApiAdapter {
x: number,
y: number,
z: number,
tileSize: number,
tileSize: number = 256,
pixelRatio: number = window?.devicePixelRatio || 1,
extentBuffer: number = 0,
): Promise<ImageData> {
return this.runLimited(() => {
return new Promise((resolve) => {
this._api.renderXYZTile(x, y, z, tileSize, pixelRatio, (tileData) => {
const data = new Uint8ClampedArray(tileData);
const imageData = new ImageData(data, tileSize, tileSize);
resolve(imageData);
});
this._api.renderXYZTile(
x,
y,
z,
tileSize,
pixelRatio,
extentBuffer,
(tileData) => {
const data = new Uint8ClampedArray(tileData);
const imageData = new ImageData(data, tileSize, tileSize);
resolve(imageData);
},
);
});
});
}
Expand Down
29 changes: 29 additions & 0 deletions sites/dev/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,35 @@ <h2>OpenLayers: Canvas Tile</h2>
<section id="openlayers_xyz" class="tab-panel">
<h2>OpenLayers: XYZ Tiles</h2>
<div id="ol-demo-xyz" class="demo"></div>
<div class="canvas-options">
<label
title="Factor will be multiploed with the tiles width in map units."
for="extentBufferFactor"
>Extent Buffer Factor:</label
>
<input
title="Factor will be multiploed with the tiles width in map units."
type="range"
min="0"
max="2"
step="0.01"
value="0.5"
name="extentBufferFactor"
id="extentBufferFactor"
oninput="this.nextElementSibling.value = (Math.round(this.value * 100) / 100).toFixed(2)"
/>
<output>0.50</output>

<div class="seperator">&nbsp;</div>

<label for="xyzBaseMap">OSM Basemap:</label>
<input
type="checkbox"
checked="checked"
name="xyzBaseMap"
id="xyzBaseMap"
/>
</div>
<p>
With the
<a href="https://github.com/qgis/qgis-js" target="_blank"
Expand Down
14 changes: 14 additions & 0 deletions sites/dev/src/demo.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ a.source {
resize: both;
}

.canvas-options {
margin: -1em 0 2em 0;
padding: 1em;
border: 1px solid #ccc;
background-color: #ffffff;
text-align: center;
}

.canvas-options .seperator {
display: inline-block;
margin: 0 0.5em;
border-left: 1px solid #ccc;
}

.code {
overflow: auto;
border: 1px solid #ccc;
Expand Down
Loading

0 comments on commit 2e8b293

Please sign in to comment.