Skip to content

Commit

Permalink
Release version 0.2.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
francois2metz committed Jul 7, 2020
1 parent 04121f8 commit 8d40fad
Show file tree
Hide file tree
Showing 5 changed files with 400 additions and 52 deletions.
34 changes: 32 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,12 @@ map.addControl(indoorEqual);
- [Parameters](#parameters-2)
- [onAdd](#onadd)
- [onRemove](#onremove)
- [updateLevel](#updatelevel)
- [setLevel](#setlevel)
- [Parameters](#parameters-3)
- [updateLevel](#updatelevel)
- [Parameters](#parameters-4)
- [loadSprite](#loadsprite)
- [Parameters](#parameters-5)
- [IndoorEqual#levelschange](#indoorequallevelschange)
- [IndoorEqual#levelchange](#indoorequallevelchange)

Expand All @@ -76,6 +80,7 @@ Load the indoor= source and layers in your map.
- `options` **[object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** (optional, default `{}`)
- `options.url` **[url](https://developer.mozilla.org/docs/Web/API/URL/URL)?** Override the default tiles URL (<https://tiles.indoorequal.org/>).
- `options.apiKey` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** The API key if you use the default tile URL (get your free key at [indoorequal.com](https://indoorequal.com)).
- `options.layers` **[array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The layers to be used to style indoor= tiles.

#### Properties

Expand Down Expand Up @@ -112,14 +117,39 @@ Used when adding the control via the map instance: map.addControl(indoorEqual)
Remove the level control
Used when removing the control via the map instance: map.removeControl(indoorEqual)

#### setLevel

Set the displayed level.

##### Parameters

- `level` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the level to be displayed

#### updateLevel

Update the displayed level.
Set the displayed level.

##### Parameters

- `level` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the level to be displayed

**Meta**

- **deprecated**: This is deprecated.


#### loadSprite

Load a sprite and add all images to the map

##### Parameters

- `baseUrl` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the baseUrl where to load the sprite
- `options` **[object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** (optional, default `{}`)
- `options.update` **[url](https://developer.mozilla.org/docs/Web/API/URL/URL)?** Update existing image (default false)

Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** It resolves an hash of images.

### IndoorEqual#levelschange

Emitted when the list of available levels has been updated
Expand Down
207 changes: 183 additions & 24 deletions dist/mapbox-gl-indoorequal.cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class LevelControl {
if (level == this.indoorequal.level) {
button.classList.add('mapboxgl-ctrl-active');
}
button.addEventListener('click', () => { this.indoorequal.updateLevel(level); });
button.addEventListener('click', () => { this.indoorequal.setLevel(level); });
this.$el.appendChild(button);
});
}
Expand Down Expand Up @@ -96,9 +96,6 @@ const layers = [
"level"
]
],
layout: {
visibility: "visible"
},
paint: {
"fill-color": "white"
}
Expand All @@ -117,9 +114,6 @@ const layers = [
"platform"
]
],
"layout": {
"visibility": "visible"
},
"paint": {
"line-color": "#bfbfbf",
"line-width": 1
Expand All @@ -137,9 +131,6 @@ const layers = [
"column"
]
],
"layout": {
"visibility": "visible"
},
"paint": {
"fill-color": "#bfbfbf"
}
Expand All @@ -157,9 +148,6 @@ const layers = [
"wall"
]
],
"layout": {
"visibility": "visible"
},
"paint": {
"line-color": "gray",
"line-width": 2
Expand All @@ -172,9 +160,6 @@ const layers = [
"filter": [
"all"
],
"layout": {
"visibility": "visible",
},
"paint": {
"line-color": "gray",
"line-dasharray": [
Expand Down Expand Up @@ -273,6 +258,145 @@ const layers = [
}
];

function createImage(image, {width, height}, channels, data) {
if (!data) {
data = new Uint8Array(width * height * channels);
} else if (data instanceof Uint8ClampedArray) {
data = new Uint8Array(data.buffer);
} else if (data.length !== width * height * channels) {
throw new RangeError('mismatched image size');
}
image.width = width;
image.height = height;
image.data = data;
return image;
}

function resizeImage(image, {width, height}, channels) {
if (width === image.width && height === image.height) {
return;
}

const newImage = createImage({}, {width, height}, channels);

copyImage(image, newImage, {x: 0, y: 0}, {x: 0, y: 0}, {
width: Math.min(image.width, width),
height: Math.min(image.height, height)
}, channels);

image.width = width;
image.height = height;
image.data = newImage.data;
}

function copyImage(srcImg, dstImg, srcPt, dstPt, size, channels) {
if (size.width === 0 || size.height === 0) {
return dstImg;
}

if (size.width > srcImg.width ||
size.height > srcImg.height ||
srcPt.x > srcImg.width - size.width ||
srcPt.y > srcImg.height - size.height) {
throw new RangeError('out of range source coordinates for image copy');
}

if (size.width > dstImg.width ||
size.height > dstImg.height ||
dstPt.x > dstImg.width - size.width ||
dstPt.y > dstImg.height - size.height) {
throw new RangeError('out of range destination coordinates for image copy');
}

const srcData = srcImg.data;
const dstData = dstImg.data;

for (let y = 0; y < size.height; y++) {
const srcOffset = ((srcPt.y + y) * srcImg.width + srcPt.x) * channels;
const dstOffset = ((dstPt.y + y) * dstImg.width + dstPt.x) * channels;
for (let i = 0; i < size.width * channels; i++) {
dstData[dstOffset + i] = srcData[srcOffset + i];
}
}
return dstImg;
}

// Not premultiplied, because ImageData is not premultiplied.
// UNPACK_PREMULTIPLY_ALPHA_WEBGL must be used when uploading to a texture.
class RGBAImage {
constructor(size, data) {
createImage(this, size, 4, data);
}

resize(size) {
resizeImage(this, size, 4);
}

replace(data, copy) {
if (copy) {
this.data.set(data);
} else if (data instanceof Uint8ClampedArray) {
this.data = new Uint8Array(data.buffer);
} else {
this.data = data;
}
}

clone() {
return new RGBAImage({width: this.width, height: this.height}, new Uint8Array(this.data));
}

static copy(srcImg, dstImg, srcPt, dstPt, size) {
copyImage(srcImg, dstImg, srcPt, dstPt, size, 4);
}
}

function getImageData(img, padding) {
const canvas = window.document.createElement('canvas');
const context = canvas.getContext('2d');
if (!context) {
throw new Error('failed to create canvas 2d context');
}
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0, img.width, img.height);
return context.getImageData(0, 0, img.width, img.height);
}

function loadSprite(baseUrl) {
const format = window.devicePixelRatio > 1 ? '@2x' : '';
let json, image;

const jsonRequest = fetch(`${baseUrl}${format}.json`)
.then(r => r.json())
.then(r => json = r);

const imageRequest = fetch(`${baseUrl}${format}.png`)
.then(r => r.blob())
.then(r => {
image = new Image();
image.src = URL.createObjectURL(r);
return new Promise((resolve, reject) => {
image.onload = () => resolve();
image.onerror = () => reject();
});
});

return Promise.all([jsonRequest, imageRequest])
.then(() => {
const imageData = getImageData(image);
const result = {};

for (const id in json) {
const {width, height, x, y, sdf, pixelRatio, stretchX, stretchY, content} = json[id];
const data = new RGBAImage({width, height});
RGBAImage.copy(imageData, data, {x, y}, {x: 0, y: 0}, {width, height});
result[id] = {data, pixelRatio, sdf, stretchX, stretchY, content};
}
return result;
});
}

const SOURCE_ID = 'indoorequal';

/**
Expand All @@ -281,6 +405,7 @@ const SOURCE_ID = 'indoorequal';
* @param {object} options
* @param {url} [options.url] Override the default tiles URL (https://tiles.indoorequal.org/).
* @param {string} [options.apiKey] The API key if you use the default tile URL (get your free key at [indoorequal.com](https://indoorequal.com)).
* @param {array} [options.layers] The layers to be used to style indoor= tiles.
* @property {string} level The current level displayed
* @property {array} levels The levels that can be displayed in the current view
* @fires IndoorEqual#levelschange
Expand All @@ -289,14 +414,15 @@ const SOURCE_ID = 'indoorequal';
*/
class IndoorEqual {
constructor(map, options = {}) {
const defaultOpts = { url: 'https://tiles.indoorequal.org/' };
const opts = { ...defaultOpts, ...options };
const defaultOpts = { url: 'https://tiles.indoorequal.org/', layers };
const opts = { ...defaultOpts, ...options };
if (opts.url === defaultOpts.url && !opts.apiKey) {
throw 'You must register your apiKey at https://indoorequal.com before and set it as apiKey param.';
}
this.map = map;
this.url = opts.url;
this.apiKey = opts.apiKey;
this.layers = opts.layers;
this.levels = [];
this.level = "0";
this.events = {};
Expand Down Expand Up @@ -351,23 +477,56 @@ class IndoorEqual {
}

/**
* Update the displayed level.
* Set the displayed level.
* @param {string} level the level to be displayed
* @fires IndoorEqual#levelchange
*/
updateLevel(level) {
setLevel(level) {
this.level = level;
this._updateFilters();
this._emitLevelChange();
}

/**
* Set the displayed level.
* @deprecated
* @param {string} level the level to be displayed
* @fires IndoorEqual#levelchange
*/
updateLevel(level) {
this.setLevel(level);
}

/**
* Load a sprite and add all images to the map
* @param {string} baseUrl the baseUrl where to load the sprite
* @param {object} options
* @param {url} [options.update] Update existing image (default false)
* @return {Promise} It resolves an hash of images.
*/
loadSprite(baseUrl, options = {}) {
const opts = { update: false, ...options };
return loadSprite(baseUrl)
.then((sprite) => {
for (const id in sprite) {
const { data, ...options } = sprite[id];
if (!this.map.hasImage(id)) {
this.map.addImage(id, data, options);
} else if (opts.update) {
this.map.updateImage(id, data);
}
}
return sprite;
});
}

_addSource() {
const queryParams = this.apiKey ? `?key=${this.apiKey}` : '';
this.map.addSource(SOURCE_ID, {
type: 'vector',
url: `${this.url}${queryParams}`
});
layers.forEach((layer) => {
this.layers.forEach((layer) => {
this.map.addLayer({
source: SOURCE_ID,
...layer
Expand All @@ -382,14 +541,14 @@ class IndoorEqual {
}

_updateFilters() {
layers.forEach((layer) => {
this.map.setFilter(layer.id, [ ...layer.filter, ['==', 'level', this.level]]);
this.layers.forEach((layer) => {
this.map.setFilter(layer.id, [ ...layer.filter || ['all'], ['==', 'level', this.level]]);
});
}

_refreshAfterLevelsUpdate() {
if (!this.levels.includes(this.level)) {
this.updateLevel('0');
this.setLevel('0');
}
}

Expand Down
Loading

0 comments on commit 8d40fad

Please sign in to comment.