@mappable-world/mappable-entity-tile-loader package
Mappable JS API package loading data by tiles.
Allows you to load and display on the map only those objects that are included in the tile areas
displayed on the map.
The data is loaded tile-by-tile, so you don't have to load all the data at once.
How use
The package is located in the dist
folder:
dist/types
TypeScript typesdist/esm
es6 modules for direct connection in your projectdist/index.js
Mappable JS Module
to use Mappable JS Module you need to add your module loading handler to JS API
Recommended use MMapEntityTileLoader
as usual npm package:
npm i @mappable-world/mappable-entity-tile-loader
and dynamic import
const {MMapEntityTileLoader} = await import('@mappable-world/mappable-entity-tile-loader/dist/esm/index');
But you can use CDN:
Development
mappable.import.loaders.unshift(async (pkg) => {
if (!pkg.startsWith('@mappable-world/mappable-entity-tile-loader')) {
return;
}
await mappable.import.script(`./node_modules/@mappable-world/mappable-entity-tile-loader/dist/index.js`);
return window[`${pkg}`];
});
Production
mappable.import.loaders.unshift(async (pkg) => {
if (!pkg.includes('@mappable-world/mappable-entity-tile-loader')) {
return;
}
await mappable.import.script(`https://unpkg.com/${pkg}/dist/index.js`);
return window[`${pkg}`];
});
and in your final code just use mappable.import
const {MMapFeature, MMapDefaultFeaturesLayer} = mappable;
const {MMapEntityTileLoader} = await mappable.import('@mappable-world/mappable-entity-tile-loader@1.0.0');
map.addChild(new MMapDefaultFeaturesLayer());
map.addChild(
new MMapEntityTileLoader({
removalDelay: 500,
tileSize: 256,
getFeatureId: (feature) => feature.id,
fetchTile: ({tx, ty, tz, sginal}) => {
return fetch(`https://geodata.example/${tx}/${ty}/${tz}`, {signal}).then((r) => r.json());
},
entity: (feature) =>
new MMapFeature({id: feature.id.toString(), geometry: feature.geometry, properties: feature.properties}),
onFeatureAdd: (feature) => {
console.log(feature);
},
onFeatureRemove: (feature) => {
console.log(feature);
}
})
);
API
Constructor parameters MMapEntityTileLoader
:
import type {GenericFeature, LngLat, MMapEntity} from '@mappable-world/mappable-types';
export type GeojsonFeature = GenericFeature<LngLat>;
export interface MMapEntityTileLoaderProps {
readonly tileSize: number;
fetchTile: (args: {tx: number; ty: number; tz: number; signal: AbortSignal}) => Promise<GeojsonFeature[]>;
getFeatureId: (feature: GeojsonFeature) => string;
entity: (feature: GeojsonFeature) => MMapEntity<unknown>;
onFeatureAdd: (feature: GeojsonFeature) => void | false;
onFeatureRemove: (feature: GeojsonFeature) => void | false;
removalDelay?: number;
}
And a React version:
const BOUNDS = [
[53.20890963521473, 25.52765018907181],
[57.444403818421854, 24.71096299361919]
];
const LOCATION = {bounds: BOUNDS};
const [mappableReact] = await Promise.all([mappable.import('@mappable-world/mappable-reactify'), mappable.ready]);
const reactify = mappableReact.reactify.bindTo(React, ReactDOM);
const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapControlButton, MMapControls, MMapFeature} =
reactify.module(mappable);
const {useState, useCallback} = React;
const {MMapZoomControl} = reactify.module(await mappable.import('@mappable-world/mappable-controls@0.0.1'));
const {MMapEntityTileLoader} = reactify.module(await mappable.import('@mappable-world/mappable-entity-tile-loader'));
function App() {
return (
<MMap location={LOCATION} ref={(x) => (map = x)}>
<MMapDefaultSchemeLayer />
<MMapDefaultFeaturesLayer />
<MMapControls position="right">
<MMapZoomControl />
</MMapControls>
<MMapControls position="top">
<MMapControlButton text={`urban area in loaded tiles: ${total.toFixed(2)} km2`} />
</MMapControls>
<MMapEntityTileLoader
renderDelay={100}
tileSize={TILE_SIZE}
getFeatureId={useCallback((feature) => feature.id, [])}
fetchTile={fetchTile}
entity={useCallback(
(feature) => (
<MMapFeature id={feature.id.toString()} geometry={feature.geometry} properties={feature.properties} />
),
[]
)}
onFeatureAdd={useCallback((entity) => {
setTotal((total) => total + entity.properties.area_sqkm);
}, [])}
onFeatureRemove={useCallback((entity) => {
setTotal((total) => total - entity.properties.area_sqkm);
}, [])}
/>
</MMap>
);
}
For react version, you can use renderDelay
parameter, because react will call render
function for each feature.
To avoid unnecessary calls, you can set the delay for applying the changes.