-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
MVT Tile Layer #3935
MVT Tile Layer #3935
Changes from all commits
6e07ae0
03361bf
4cacef9
fa89ac4
ffabcdd
b3dfbf0
8b2877f
58bd2f8
b829766
4c64857
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import {Matrix4} from 'math.gl'; | ||
import {MVTLoader} from '@loaders.gl/mvt'; | ||
import {load} from '@loaders.gl/core'; | ||
import {COORDINATE_SYSTEM} from '@deck.gl/core'; | ||
import {GeoJsonLayer} from '@deck.gl/layers'; | ||
|
||
import TileLayer from '../tile-layer/tile-layer'; | ||
|
||
const defaultProps = Object.assign({}, TileLayer.defaultProps, { | ||
renderSubLayers: {type: 'function', value: renderSubLayers, compare: false}, | ||
urlTemplates: [] | ||
}); | ||
|
||
export default class MVTTileLayer extends TileLayer { | ||
initializeState() { | ||
super.initializeState(); | ||
const {urlTemplates} = this.props; | ||
|
||
this.state = { | ||
...this.state, | ||
urlTemplates | ||
}; | ||
} | ||
|
||
async getTileData(tileProperties) { | ||
const {urlTemplates} = this.state; | ||
|
||
if (!urlTemplates || !urlTemplates.length) { | ||
return Promise.reject(); | ||
} | ||
|
||
const templateReplacer = (_, property) => tileProperties[property]; | ||
const tileURLIndex = getTileURLIndex(tileProperties, urlTemplates.length); | ||
const tileURL = urlTemplates[tileURLIndex].replace(/\{ *([\w_-]+) *\}/g, templateReplacer); | ||
|
||
return await load(tileURL, MVTLoader); | ||
} | ||
} | ||
|
||
function renderSubLayers(tileProperties) { | ||
return new GeoJsonLayer({ | ||
...tileProperties, | ||
modelMatrix: getModelMatrix(tileProperties.tile), | ||
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN | ||
}); | ||
} | ||
|
||
function getModelMatrix(tile) { | ||
const WORLD_SIZE = 512; | ||
const worldScale = Math.pow(2, tile.z); | ||
|
||
const xScale = WORLD_SIZE / worldScale; | ||
const yScale = -xScale; | ||
|
||
const xOffset = (WORLD_SIZE * tile.x) / worldScale; | ||
const yOffset = WORLD_SIZE * (1 - tile.y / worldScale); | ||
|
||
return new Matrix4().translate([xOffset, yOffset, 0]).scale([xScale, yScale, 1]); | ||
} | ||
|
||
function getTileURLIndex({x, y}, templatesLength) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a standard schema? If yes, can you add a link to its specs? Otherwise, should we allow users to customize this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's used to bypass Domain Sharding when HTTP 2 is not available. The user can provide N tiles endpoint and this function does the splitting to each one. The tilejson spec defines a // REQUIRED. An array of tile endpoints. {z}, {x} and {y}, if present,
// are replaced with the corresponding integers. If multiple endpoints are specified, clients
// may use any combination of endpoints. All endpoints MUST return the same
// content for the same URL. The array MUST contain at least one endpoint.
"tiles": [
"http://localhost:8888/admin/1.0.0/world-light,broadband/{z}/{x}/{y}.png"
] |
||
return Math.abs(x + y) % templatesLength; | ||
} | ||
|
||
MVTTileLayer.layerName = 'MVTTileLayer'; | ||
MVTTileLayer.defaultProps = defaultProps; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import test from 'tape-catch'; | ||
import {generateLayerTests, testLayer} from '@deck.gl/test-utils'; | ||
import {MVTTileLayer} from '@deck.gl/geo-layers'; | ||
|
||
test('MVTTileLayer', t => { | ||
const testCases = generateLayerTests({ | ||
Layer: MVTTileLayer, | ||
assert: t.ok, | ||
sampleProps: { | ||
urlTemplates: [ | ||
'https://a.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png' | ||
] | ||
}, | ||
onBeforeUpdate: ({testCase}) => t.comment(testCase.title) | ||
}); | ||
testLayer({Layer: MVTTileLayer, testCases, onError: t.notOk}); | ||
t.end(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Start a documentation page in
docs/layers
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point!