Skip to content

Commit

Permalink
Add ImageSource#updateImage (#7342)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcervelli authored and ryanhamley committed Oct 2, 2018
1 parent 53cf0d6 commit efb91b6
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 35 deletions.
69 changes: 69 additions & 0 deletions debug/update_image.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<title>Mapbox GL JS debug page</title>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel='stylesheet' href='/dist/mapbox-gl.css' />
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
</style>
</head>

<body>
<div id='map'></div>

<script src='/dist/mapbox-gl-dev.js'></script>
<script src='/debug/access_token_generated.js'></script>
<script>

const map = new mapboxgl.Map({
container: 'map',
minZoom: 1,
zoom: 6,
center: [-76, 43.5],
style: 'mapbox://styles/mapbox/dark-v9',
hash: false
});

const path = "/docs/pages/assets/";

const frameCount = 5;

const coordinates = [
[-80.425, 46.437],
[-71.516, 46.437],
[-71.516, 37.936],
[-80.425, 37.936]
];

map.on("load", () => {
let currentImage = 0;
const getPath = () => `${path}radar${currentImage}.gif`;

map.addSource("radar", {
type: "image",
url: getPath(),
coordinates
});
map.addLayer({
id: "radar-layer",
"type": "raster",
"source": "radar",
"paint": {
"raster-resampling": "nearest",
"raster-fade-duration": 0
}
});

setInterval(() => {
currentImage = (currentImage + 1) % frameCount;
map.getSource("radar").updateImage({ url: getPath() });
}, 200);
});

</script>

</body>
</html>
56 changes: 27 additions & 29 deletions docs/pages/example/animate-images.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,37 @@
center: [-75.789, 41.874]
});

map.on('load', function() {
var frameCount = 5;
var currentImage = 0;

function getPath() {
return "https://www.mapbox.com/mapbox-gl-js/assets/radar" + currentImage + ".gif";
}

var frameCount = 5;
for (var i = 0; i < frameCount; i++) {
map.on('load', function() {

map.addLayer({
id: 'radar' + i,
source: {
type: 'image',
url: 'https://www.mapbox.com/mapbox-gl-js/assets/radar' + i + '.gif',
coordinates: [
[-80.425, 46.437],
[-71.516, 46.437],
[-71.516, 37.936],
[-80.425, 37.936]
]
},
type: 'raster',
paint: {
'raster-opacity': 0,
'raster-opacity-transition': {
duration: 0
}
}
});
}
map.addSource("radar", {
type: "image",
url: getPath(),
coordinates: [
[-80.425, 46.437],
[-71.516, 46.437],
[-71.516, 37.936],
[-80.425, 37.936]
]
});
map.addLayer({
id: "radar-layer",
"type": "raster",
"source": "radar",
"paint": {
"raster-fade-duration": 0
}
});

var frame = frameCount - 1;
setInterval(function() {
map.setPaintProperty('radar' + frame, 'raster-opacity', 0);
frame = (frame + 1) % frameCount;
map.setPaintProperty('radar' + frame, 'raster-opacity', 1);
currentImage = (currentImage + 1) % frameCount;
map.getSource("radar").updateImage({ url: getPath() });
}, 200);

});
</script>
52 changes: 46 additions & 6 deletions src/source/image_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import type {
VideoSourceSpecification
} from '../style-spec/types';

type Coordinates = [[number, number], [number, number], [number, number], [number, number]];

/**
* A data source containing an image.
* (See the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#sources-image) for detailed documentation of options.)
Expand All @@ -44,15 +46,26 @@ import type {
* ]
* });
*
* // update
* // update coordinates
* var mySource = map.getSource('some id');
* mySource.setCoordinates([
* [-76.54335737228394, 39.18579907229748],
* [-76.52803659439087, 39.1838364847587],
* [-76.5295386314392, 39.17683392507606],
* [-76.54520273208618, 39.17876344106642]
* ]);
*
*
* // update url and coordinates simultaneously
* mySource.updateImage({
* url: 'https://www.mapbox.com/images/bar.png',
* coordinates: [
* [-76.54335737228394, 39.18579907229748],
* [-76.52803659439087, 39.1838364847587],
* [-76.5295386314392, 39.17683392507606],
* [-76.54520273208618, 39.17876344106642]
* ]
* })
*
* map.removeSource('some id'); // remove
* @see [Add an image](https://www.mapbox.com/mapbox-gl-js/example/image-on-a-map/)
*/
Expand All @@ -64,12 +77,12 @@ class ImageSource extends Evented implements Source {
tileSize: number;
url: string;

coordinates: [[number, number], [number, number], [number, number], [number, number]];
coordinates: Coordinates;
tiles: {[string]: Tile};
options: any;
dispatcher: Dispatcher;
map: Map;
texture: Texture;
texture: Texture | null;
image: ImageData;
centerCoord: Coordinate;
tileID: CanonicalTileID;
Expand Down Expand Up @@ -97,7 +110,7 @@ class ImageSource extends Evented implements Source {
this.options = options;
}

load() {
load(newCoordinates?: Coordinates, successCallback?: () => void) {
this.fire(new Event('dataloading', {dataType: 'source'}));

this.url = this.options.url;
Expand All @@ -107,11 +120,38 @@ class ImageSource extends Evented implements Source {
this.fire(new ErrorEvent(err));
} else if (image) {
this.image = browser.getImageData(image);
if (newCoordinates) {
this.coordinates = newCoordinates;
}
if (successCallback) {
successCallback();
}
this._finishLoading();
}
});
}

/**
* Updates the image URL and, optionally, the coordinates. To avoid having the image flash after changing,
* set the `raster-fade-duration` paint property on the raster layer to 0.
*
* @param {Object} options
* @param {string} [options.url] Required image URL.
* @param {Array<Array<number>>} [options.coordinates] Four geographical coordinates,
* represented as arrays of longitude and latitude numbers, which define the corners of the image.
* The coordinates start at the top left corner of the image and proceed in clockwise order.
* They do not have to represent a rectangle.
* @returns {ImageSource} this
*/
updateImage(options: {url: string, coordinates?: Coordinates}) {
if (!this.image || !options.url) {
return this;
}
this.options.url = options.url;
this.load(options.coordinates, () => { this.texture = null; });
return this;
}

_finishLoading() {
if (this.map) {
this.setCoordinates(this.coordinates);
Expand All @@ -133,7 +173,7 @@ class ImageSource extends Evented implements Source {
* They do not have to represent a rectangle.
* @returns {ImageSource} this
*/
setCoordinates(coordinates: [[number, number], [number, number], [number, number], [number, number]]) {
setCoordinates(coordinates: Coordinates) {
this.coordinates = coordinates;

// Calculate which mercator tile is suitable for rendering the video in
Expand Down
47 changes: 47 additions & 0 deletions test/unit/source/image_source.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,53 @@ test('ImageSource', (t) => {
t.end();
});

t.test('updates url from updateImage', (t) => {
const source = createSource({ url : '/image.png' });
const map = new StubMap();
const spy = t.spy(map, '_transformRequest');
source.onAdd(map);
respond();
t.ok(spy.calledOnce);
t.equal(spy.getCall(0).args[0], '/image.png');
t.equal(spy.getCall(0).args[1], 'Image');
source.updateImage({ url: '/image2.png' });
respond();
t.ok(spy.calledTwice);
t.equal(spy.getCall(1).args[0], '/image2.png');
t.equal(spy.getCall(1).args[1], 'Image');
t.end();
});

t.test('sets coordinates', (t) => {
const source = createSource({ url : '/image.png' });
const map = new StubMap();
source.onAdd(map);
respond();
const beforeSerialized = source.serialize();
t.deepEqual(beforeSerialized.coordinates, [[0, 0], [1, 0], [1, 1], [0, 1]]);
source.setCoordinates([[0, 0], [-1, 0], [-1, -1], [0, -1]]);
const afterSerialized = source.serialize();
t.deepEqual(afterSerialized.coordinates, [[0, 0], [-1, 0], [-1, -1], [0, -1]]);
t.end();
});

t.test('sets coordinates via updateImage', (t) => {
const source = createSource({ url : '/image.png' });
const map = new StubMap();
source.onAdd(map);
respond();
const beforeSerialized = source.serialize();
t.deepEqual(beforeSerialized.coordinates, [[0, 0], [1, 0], [1, 1], [0, 1]]);
source.updateImage({
url: '/image2.png',
coordinates: [[0, 0], [-1, 0], [-1, -1], [0, -1]]
});
respond();
const afterSerialized = source.serialize();
t.deepEqual(afterSerialized.coordinates, [[0, 0], [-1, 0], [-1, -1], [0, -1]]);
t.end();
});

t.test('fires data event when content is loaded', (t) => {
const source = createSource({ url : '/image.png' });
source.on('data', (e) => {
Expand Down

0 comments on commit efb91b6

Please sign in to comment.