Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

loadImage の後方互換性のための処理を追加 #397

Merged
merged 12 commits into from
Oct 28, 2024
Merged
206 changes: 206 additions & 0 deletions docs/backwardcompatibility.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
<!doctype html>
<html>

<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="./style.css">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>@geolonia/embed</title>
</head>

<body>
<h1>@geolonia/embed</h1>

後方互換性テストのためのサンプルコードです。

<h2>loadImage</h2>
<div>MapLibre GL JS v4.4.1 の から、loadImage の呼び出し方が以下のように変更になりました。Embed API では後方互換性を保つため、v4.4.1 以前の書き方も引き続きサポートしています。</div>
<a href="https://github.com/maplibre/maplibre-gl-js/pull/3422/" target="_blank">関連する ISSUE: Remove callback from loadImage</a>
<br/>
<code>
<pre>
// v4.4.1 以降
map.loadImage(url)

// v4.4.1 以前
map.loadImage(url, callback)</pre>
</code>

<div class="example">
<h2>v4.4.1 以降</h2>
<div
id="my-map1"
class="geolonia"
data-lat="35.681236"
data-lng="139.767125"
data-zoom="9"
data-marker="off"
></div>
<pre>
var map1 = new geolonia.Map('my-map1');
map1.on('load', async () => {
image = await map1.loadImage('https://upload.wikimedia.org/wikipedia/commons/7/7c/201408_cat.png');
map1.addImage('cat', image.data);
map1.addSource('point', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [139.767125, 35.681236]
}
}
]
}
});
map1.addLayer({
'id': 'points',
'type': 'symbol',
'source': 'point',
'layout': {
'icon-image': 'cat',
'icon-size': 0.25
}
});
});
</pre>
</div>

<div class="example">
<h2>v4.4.1 以前</h2>
<div
id="my-map2"
class="geolonia"
data-lat="35.681236"
data-lng="139.767125"
data-zoom="9"
data-marker="off"
></div>
<pre>
var map2 = new geolonia.Map('my-map2');
map2.on('load', () => {
map2.loadImage(
'https://upload.wikimedia.org/wikipedia/commons/7/7c/201408_cat.png',
(error, image) => {
if (error) throw error;
map2.addImage('cat', image);
}
);
map2.addSource('point', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [139.767125, 35.681236]
}
}
]
}
});
map2.addLayer({
'id': 'points',
'type': 'symbol',
'source': 'point',
'layout': {
'icon-image': 'cat',
'icon-size': 0.25
}
});
});
</pre>
</div>

<footer>
&copy; <a href="https://geolonia.com">geolonia.com</a>
</footer>

<script>
var examples = document.querySelectorAll('.example');
for (var i = 0; i < examples.length; i++) {
var example = examples[i];
var html = example.querySelector('.geolonia, #my-map').outerHTML;
var pre = document.createElement('pre');
pre.innerText = html.replace(/(<div.+?)(>)/g, "$1\n$2").replace(/ ([^ ]+=[^ ]+)/g, "\n $1");
example.insertBefore(pre, example.querySelector('.geolonia'));
}
</script>

<a class="forkme" href="https://github.com/geolonia/embed"><img width="149" height="149" src="https://github.blog/wp-content/uploads/2008/12/forkme_right_darkblue_121621.png?resize=149%2C149" class="attachment-full size-full" alt="Fork me on GitHub" data-recalc-dims="1"></a>

<script src="./embed?geolonia-api-key=YOUR-API-KEY"></script>
<script>
var map1 = new geolonia.Map('my-map1');
map1.on('load', async () => {
image = await map1.loadImage('https://upload.wikimedia.org/wikipedia/commons/7/7c/201408_cat.png');
map1.addImage('cat', image.data);
map1.addSource('point', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [139.767125, 35.681236]
}
}
]
}
});
map1.addLayer({
'id': 'points',
'type': 'symbol',
'source': 'point',
'layout': {
'icon-image': 'cat',
'icon-size': 0.25
}
});
});

var map2 = new geolonia.Map('my-map2');
map2.on('load', () => {
map2.loadImage(
'https://upload.wikimedia.org/wikipedia/commons/7/7c/201408_cat.png',
(error, image) => {
if (error) throw error;
map2.addImage('cat', image);
}
);
map2.addSource('point', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [139.767125, 35.681236]
}
}
]
}
});
map2.addLayer({
'id': 'points',
'type': 'symbol',
'source': 'point',
'layout': {
'icon-image': 'cat',
'icon-size': 0.25
}
});
});
</script>
</body>

</html>
5 changes: 4 additions & 1 deletion docs/embed.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/**
* MapLibre GL JS
* @license 3-Clause BSD. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v4.4.1/LICENSE.txt
*/
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"homepage": "https://github.com/geolonia/embed#readme",
"devDependencies": {
"@geolonia/eslint-config": "latest",
"@types/jsdom": "^21.1.7",
"@types/mocha": "^10.0.1",
"babel-loader": "^9.1.0",
"css-loader": "^6.7.2",
Expand Down
23 changes: 21 additions & 2 deletions src/lib/geolonia-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import parseAtts from './parse-atts';
import { SimpleStyle } from './simplestyle';
import SimpleStyleVector from './simplestyle-vector';

import { getContainer, getOptions, getSessionId, getStyle, handleRestrictedMode, isScrollable, parseControlOption, parseSimpleVector, handleErrorMode } from './util';
import { getContainer, getOptions, getSessionId, getStyle, handleRestrictedMode, isScrollable, parseControlOption, parseSimpleVector, handleErrorMode, loadImageCompatibility, GetImageCallback } from './util';

import type { MapOptions, PointLike, StyleOptions, StyleSpecification, StyleSwapOptions } from 'maplibre-gl';
import type { MapOptions, PointLike, StyleOptions, StyleSpecification, StyleSwapOptions, GetResourceResponse } from 'maplibre-gl';

export type GeoloniaMapOptions = MapOptions & { interactive?: boolean };

Expand Down Expand Up @@ -319,4 +319,23 @@ export default class GeoloniaMap extends maplibregl.Map {
super.remove.call(this);
delete (container as HTMLElement & { geoloniaMap: GeoloniaMap }).geoloniaMap;
}

/**
* Backward compatibility for breaking change of loadImage() in MapLibre GL JS v4.0.0.
* Related to https://github.com/maplibre/maplibre-gl-js/pull/3422/
* @param url
* @param callback
*/
loadImage(url: string, callback: GetImageCallback): void;
loadImage(url: string): Promise<GetResourceResponse<HTMLImageElement | ImageBitmap>>;
loadImage(url: string, callback?: GetImageCallback): Promise<GetResourceResponse<HTMLImageElement | ImageBitmap>> | void {

const promise = super.loadImage(url);

if (callback) {
loadImageCompatibility(promise, callback);
} else {
return promise;
}
}
}
2 changes: 2 additions & 0 deletions src/lib/parse-atts.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */

import parseAtts from './parse-atts';
import assert from 'assert';
import { JSDOM } from 'jsdom';
Expand Down
15 changes: 6 additions & 9 deletions src/lib/simplestyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,17 +304,14 @@ export class SimpleStyle {
},
});

this.map.on('click', `${this.options.id}-clusters`, (e) => {
this.map.on('click', `${this.options.id}-clusters`, async (e) => {
const features = this.map.queryRenderedFeatures(e.point, { layers: [`${this.options.id}-clusters`] });
const clusterId = features[0].properties.cluster_id;
this.map.getSource(`${this.options.id}-points`).getClusterExpansionZoom(clusterId, (err, zoom) => {
if (err)
return;

this.map.easeTo({
center: features[0].geometry.coordinates,
zoom: zoom,
});
const zoom = await this.map.getSource(`${this.options.id}-points`).getClusterExpansionZoom(clusterId);

this.map.easeTo({
center: features[0].geometry.coordinates,
zoom: zoom,
});
});

Expand Down
42 changes: 40 additions & 2 deletions src/lib/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict';
/* eslint-disable @typescript-eslint/ban-ts-comment */

import assert from 'assert';
import { JSDOM } from 'jsdom';
import { getContainer, getLang, getOptions, getStyle, handleMarkerOptions, isDomElement, isURL, parseControlOption, parseSimpleVector, sanitizeDescription } from './util';
import { getContainer, getLang, getOptions, getStyle, handleMarkerOptions, isDomElement, isURL, parseControlOption, parseSimpleVector, sanitizeDescription, loadImageCompatibility } from './util';

const base = 'https://base.example.com/parent/';

Expand Down Expand Up @@ -62,6 +62,7 @@ describe('Tests for util.js', () => {
<div id="test-element"></div>
</body></html>`);

// @ts-ignore
global.window = dom.window;
global.document = dom.window.document;

Expand Down Expand Up @@ -89,6 +90,7 @@ describe('Tests for util.js', () => {
<div id="test-element"></div>
</body></html>`);

// @ts-ignore
global.window = dom.window;
global.document = dom.window.document;

Expand Down Expand Up @@ -235,3 +237,39 @@ describe('Tests for util.js', () => {
});
});
});


describe('loadImageCompatibility', () => {
it('should call the callback with response data when the promise resolves', (done) => {
// モックされた成功した promise
const mockResponse = {
data: new Image(),
cacheControl: 'public, max-age=3600',
expires: '1609459200',
};
const promise = Promise.resolve(mockResponse);

loadImageCompatibility(promise, (error, data, expiry) => {
assert.equal(error, null);
assert.deepEqual(data, mockResponse.data);
assert.deepEqual(expiry, {
cacheControl: mockResponse.cacheControl,
expires: mockResponse.expires,
});
done();
});
});

it('should call the callback with error when the promise rejects', (done) => {
// モックされた失敗した promise
const mockError = new Error('Failed to load image');
const promise = Promise.reject(mockError);

loadImageCompatibility(promise, (error, data, expiry) => {
assert.deepEqual(error, mockError);
assert.strictEqual(data, undefined);
assert.strictEqual(expiry, undefined);
done();
});
});
});
Loading
Loading