Skip to content

Commit

Permalink
loadImage の後方互換性のための処理を追加 (#397)
Browse files Browse the repository at this point in the history
* Backward compatibility for loadImage
* 後方互換性の確認用HTMLを追加
* 後方互換を保つ処理を切り出してテスト
* コメントを修正
---------

Co-authored-by: Keitaroh Kobayashi <[email protected]>
  • Loading branch information
naogify and keichan34 authored Oct 28, 2024
1 parent 0a8be3b commit 645c2d2
Show file tree
Hide file tree
Showing 9 changed files with 385 additions and 71 deletions.
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 @@ -297,17 +297,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

0 comments on commit 645c2d2

Please sign in to comment.