Merge ae55082cd8
into 3110cab18f
32
public/resources/gallery/config.json
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"paths": {
|
||||||
|
"root": "/usr/src/app/node_modules/tileserver-gl-styles",
|
||||||
|
"fonts": "fonts",
|
||||||
|
"styles": "styles",
|
||||||
|
"mbtiles": "/data",
|
||||||
|
"pmtiles": "/data"
|
||||||
|
},
|
||||||
|
"staticAttributionText": "© OpenStreetMap",
|
||||||
|
"watermark": "THIS IS A TEST WATERMARK",
|
||||||
|
"allowRemoteMarkerIcons": true
|
||||||
|
},
|
||||||
|
"styles": {
|
||||||
|
"basic-preview": {
|
||||||
|
"style": "basic-preview/style.json",
|
||||||
|
"tilejson": {
|
||||||
|
"bounds": [
|
||||||
|
8.275,
|
||||||
|
47.225,
|
||||||
|
8.8,
|
||||||
|
47.533
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"v3": {
|
||||||
|
"mbtiles": "/usr/src/app/public/resources/gallery/zurich_switzerland.mbtiles"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
public/resources/gallery/encoded-path-auto.png
Normal file
After Width: | Height: | Size: 60 KiB |
127
public/resources/gallery/gallery.html
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Tileserver-gl tests</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<script>
|
||||||
|
const module = {};
|
||||||
|
</script>
|
||||||
|
<script src="pixelmatch-5.3.0.0.js"></script>
|
||||||
|
<style>
|
||||||
|
img, canvas {
|
||||||
|
margin: 0 6px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body onload="loaded()">
|
||||||
|
<h1>Tileserver-gl tests</h1>
|
||||||
|
<div>A fast way to visually check for regressions. Each row shows: a test picture, the expected output, then the difference with <a href="https://github.com/mapbox/pixelmatch#pixelmatch">pixelmatch</a>.</div>
|
||||||
|
<div>Put <i>zurich_switzerland.mbtiles</i> in public/resources/gallery/ then run with:</div>
|
||||||
|
<pre>docker build . && docker run --rm -it -p 8080:8080 $(docker build -q .) -V --config /usr/src/app/public/resources/gallery/config.json</pre>
|
||||||
|
<div>This page is then served at <a href="http://0.0.0.0:8080/gallery/gallery.html">http://0.0.0.0:8080/gallery/gallery.html</a></div>
|
||||||
|
|
||||||
|
<h2>Interactive vector</h2>
|
||||||
|
<iframe src="/styles/basic-preview/#11/47.379/8.5375" width="400" height="300"></iframe>
|
||||||
|
<img src="interactive-vector.png" />
|
||||||
|
|
||||||
|
<h2>Interactive raster</h2>
|
||||||
|
<iframe src="/styles/basic-preview/?raster#12/47.379/8.5375" width="400" height="300"></iframe>
|
||||||
|
<img src="interactive-raster.png" />
|
||||||
|
|
||||||
|
<h1 id="result">Loading...</h1>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const width = 400;
|
||||||
|
const height = 300;
|
||||||
|
|
||||||
|
const tests = [
|
||||||
|
['static-lat-lng', '/styles/basic-preview/static/8.5375,47.379,12/400x300.png'],
|
||||||
|
['static-bearing', '/styles/basic-preview/static/8.5375,47.379,12@180/400x300.png'],
|
||||||
|
['static-bearing-pitch', '/styles/basic-preview/static/8.5375,47.379,12@15,80/400x300.png'],
|
||||||
|
['static-pixel-ratio-2x', '/styles/basic-preview/static/8.5375,47.379,11/200x150@2x.png'],
|
||||||
|
['path-auto', '/styles/basic-preview/static/auto/400x300.png?fill=%23ff000080&path=8.53180,47.38713|8.53841,47.38248|8.53320,47.37457'],
|
||||||
|
['encoded-path-auto', '/styles/basic-preview/static/auto/400x300.png?stroke=red&width=5&path=enc:wwg`Hyu}r@fNgn@hKyh@rR{ZlP{YrJmM`PJhNbH`P`VjUbNfJ|LzM~TtLnKxQZ'],
|
||||||
|
['linecap-linejoin-round-round', '/styles/basic-preview/static/8.5375,47.379,12/400x300.png?width=30&linejoin=round&linecap=round&path=enc:uhd`Hqk_s@kiA}nAnfAqpA'],
|
||||||
|
['linecap-linejoin-bevel-square', '/styles/basic-preview/static/8.5375,47.379,12/400x300.png?width=30&linejoin=bevel&linecap=square&path=enc:uhd`Hqk_s@kiA}nAnfAqpA'],
|
||||||
|
['markers', '/styles/basic-preview/static/8.5375,47.379,12/400x300.png?marker=8.53180,47.38713|http://localhost:8080/images/logo.png|scale:0.3&marker=8.53180,47.37457|http://localhost:8080/images/logo.png|scale:0.3'],
|
||||||
|
];
|
||||||
|
|
||||||
|
function getImgData(id) {
|
||||||
|
const img = document.getElementById(id);
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = img.width;
|
||||||
|
canvas.height = img.height;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
return ctx.getImageData(0, 0, img.width, img.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
function compare(a, b, c) {
|
||||||
|
const img1 = getImgData(a);
|
||||||
|
const img2 = getImgData(b);
|
||||||
|
|
||||||
|
const cc = document.getElementById(c);
|
||||||
|
const ctx = cc.getContext('2d');
|
||||||
|
const diff = ctx.createImageData(width, height);
|
||||||
|
const numDiffPixels = pixelmatch(img1.data, img2.data, diff.data, width, height, { threshold: 0.1 });
|
||||||
|
ctx.putImageData(diff, 0, 0);
|
||||||
|
|
||||||
|
return numDiffPixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [id, url] of tests) {
|
||||||
|
const h2 = document.createElement('h2');
|
||||||
|
h2.innerText = id;
|
||||||
|
const a = document.createElement('img');
|
||||||
|
a.src = url;
|
||||||
|
a.id = 'a_' + id;
|
||||||
|
const b = document.createElement('img');
|
||||||
|
b.src = id + '.png';
|
||||||
|
b.id = 'b_' + id;
|
||||||
|
const c = document.createElement('canvas');
|
||||||
|
c.width = width;
|
||||||
|
c.height = height;
|
||||||
|
c.id = 'c_' + id;
|
||||||
|
document.body.appendChild(h2);
|
||||||
|
document.body.appendChild(a);
|
||||||
|
document.body.appendChild(b);
|
||||||
|
document.body.appendChild(c);
|
||||||
|
}
|
||||||
|
console.log('Init done.');
|
||||||
|
|
||||||
|
function loaded() {
|
||||||
|
console.log('Loading done.');
|
||||||
|
|
||||||
|
let success = true;
|
||||||
|
for (const [id] of tests) {
|
||||||
|
const numDiffPixels = compare('a_' + id, 'b_' + id, 'c_' + id);
|
||||||
|
if (numDiffPixels > 0) {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const r = document.getElementById('result');
|
||||||
|
r.innerText = success ? 'Success' : 'Failure';
|
||||||
|
r.style.color = success ? 'green' : 'red';
|
||||||
|
|
||||||
|
console.log('Compare done.');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
More tests we could write:
|
||||||
|
<br>
|
||||||
|
- endpoint /styles/{id}/static/{minx},{miny},{maxx},{maxy}/{width}x{height}[@2x].{format} (area-based)
|
||||||
|
<br>
|
||||||
|
- arg latlng - indicates coordinates are in lat,lng
|
||||||
|
<br>
|
||||||
|
- padding
|
||||||
|
<br>
|
||||||
|
- border + borderwidth
|
||||||
|
<br>
|
||||||
|
- fill|stroke|width global vs local
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
public/resources/gallery/interactive-raster.png
Normal file
After Width: | Height: | Size: 125 KiB |
BIN
public/resources/gallery/interactive-vector.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
public/resources/gallery/linecap-linejoin-bevel-square.png
Normal file
After Width: | Height: | Size: 90 KiB |
BIN
public/resources/gallery/linecap-linejoin-round-round.png
Normal file
After Width: | Height: | Size: 90 KiB |
BIN
public/resources/gallery/markers.png
Normal file
After Width: | Height: | Size: 95 KiB |
BIN
public/resources/gallery/path-auto.png
Normal file
After Width: | Height: | Size: 102 KiB |
8
public/resources/gallery/pixelmatch-5.3.0.0.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/**
|
||||||
|
* Minified by jsDelivr using Terser v5.10.0.
|
||||||
|
* Original file: /npm/pixelmatch@5.3.0/index.js
|
||||||
|
*
|
||||||
|
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
||||||
|
*/
|
||||||
|
"use strict";module.exports=pixelmatch;const defaultOptions={threshold:.1,includeAA:!1,alpha:.1,aaColor:[255,255,0],diffColor:[255,0,0],diffColorAlt:null,diffMask:!1};function pixelmatch(t,e,r,n,i,a){if(!isPixelData(t)||!isPixelData(e)||r&&!isPixelData(r))throw new Error("Image data: Uint8Array, Uint8ClampedArray or Buffer expected.");if(t.length!==e.length||r&&r.length!==t.length)throw new Error("Image sizes do not match.");if(t.length!==n*i*4)throw new Error("Image data size does not match width/height.");a=Object.assign({},defaultOptions,a);const l=n*i,o=new Uint32Array(t.buffer,t.byteOffset,l),f=new Uint32Array(e.buffer,e.byteOffset,l);let s=!0;for(let t=0;t<l;t++)if(o[t]!==f[t]){s=!1;break}if(s){if(r&&!a.diffMask)for(let e=0;e<l;e++)drawGrayPixel(t,4*e,a.alpha,r);return 0}const d=35215*a.threshold*a.threshold;let u=0;for(let l=0;l<i;l++)for(let o=0;o<n;o++){const f=4*(l*n+o),s=colorDelta(t,e,f,f);Math.abs(s)>d?a.includeAA||!antialiased(t,o,l,n,i,e)&&!antialiased(e,o,l,n,i,t)?(r&&drawPixel(r,f,...s<0&&a.diffColorAlt||a.diffColor),u++):r&&!a.diffMask&&drawPixel(r,f,...a.aaColor):r&&(a.diffMask||drawGrayPixel(t,f,a.alpha,r))}return u}function isPixelData(t){return ArrayBuffer.isView(t)&&1===t.constructor.BYTES_PER_ELEMENT}function antialiased(t,e,r,n,i,a){const l=Math.max(e-1,0),o=Math.max(r-1,0),f=Math.min(e+1,n-1),s=Math.min(r+1,i-1),d=4*(r*n+e);let u,c,h,b,g=e===l||e===f||r===o||r===s?1:0,x=0,y=0;for(let i=l;i<=f;i++)for(let a=o;a<=s;a++){if(i===e&&a===r)continue;const l=colorDelta(t,t,d,4*(a*n+i),!0);if(0===l){if(g++,g>2)return!1}else l<x?(x=l,u=i,c=a):l>y&&(y=l,h=i,b=a)}return 0!==x&&0!==y&&(hasManySiblings(t,u,c,n,i)&&hasManySiblings(a,u,c,n,i)||hasManySiblings(t,h,b,n,i)&&hasManySiblings(a,h,b,n,i))}function hasManySiblings(t,e,r,n,i){const a=Math.max(e-1,0),l=Math.max(r-1,0),o=Math.min(e+1,n-1),f=Math.min(r+1,i-1),s=4*(r*n+e);let d=e===a||e===o||r===l||r===f?1:0;for(let i=a;i<=o;i++)for(let a=l;a<=f;a++){if(i===e&&a===r)continue;const l=4*(a*n+i);if(t[s]===t[l]&&t[s+1]===t[l+1]&&t[s+2]===t[l+2]&&t[s+3]===t[l+3]&&d++,d>2)return!0}return!1}function colorDelta(t,e,r,n,i){let a=t[r+0],l=t[r+1],o=t[r+2],f=t[r+3],s=e[n+0],d=e[n+1],u=e[n+2],c=e[n+3];if(f===c&&a===s&&l===d&&o===u)return 0;f<255&&(f/=255,a=blend(a,f),l=blend(l,f),o=blend(o,f)),c<255&&(c/=255,s=blend(s,c),d=blend(d,c),u=blend(u,c));const h=rgb2y(a,l,o),b=rgb2y(s,d,u),g=h-b;if(i)return g;const x=rgb2i(a,l,o)-rgb2i(s,d,u),y=rgb2q(a,l,o)-rgb2q(s,d,u),M=.5053*g*g+.299*x*x+.1957*y*y;return h>b?-M:M}function rgb2y(t,e,r){return.29889531*t+.58662247*e+.11448223*r}function rgb2i(t,e,r){return.59597799*t-.2741761*e-.32180189*r}function rgb2q(t,e,r){return.21147017*t-.52261711*e+.31114694*r}function blend(t,e){return 255+(t-255)*e}function drawPixel(t,e,r,n,i){t[e+0]=r,t[e+1]=n,t[e+2]=i,t[e+3]=255}function drawGrayPixel(t,e,r,n){const i=blend(rgb2y(t[e+0],t[e+1],t[e+2]),r*t[e+3]/255);drawPixel(n,e,i,i,i)}
|
||||||
|
//# sourceMappingURL=/sm/c63ff0ee83224674e743a369cf841b9f0a69d1938d5d74c59d8ae9cf4947611a.map
|
BIN
public/resources/gallery/static-bearing-pitch.png
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
public/resources/gallery/static-bearing.png
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
public/resources/gallery/static-lat-lng.png
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
public/resources/gallery/static-pixel-ratio-2x.png
Normal file
After Width: | Height: | Size: 68 KiB |