Skip to content

Commit

Permalink
Rebase maplibre#938 (pmtiles) onto main
Browse files Browse the repository at this point in the history
Still contains old bugs

Co-authored-by: Brandon Liu <[email protected]>
Co-authored-by: Pirmin Kalberer <[email protected]>
  • Loading branch information
3 people committed Dec 26, 2024
1 parent c6174a5 commit 60ad65a
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 22 deletions.
26 changes: 26 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"maputnik-design": "github:maputnik/design#172b06c",
"ol": "^6.14.1",
"ol-mapbox-style": "^7.1.1",
"pmtiles": "^3.2.0",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-accessible-accordion": "^5.0.0",
Expand Down
52 changes: 31 additions & 21 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import get from 'lodash.get'
import {unset} from 'lodash'
import {arrayMoveMutable} from 'array-move'
import hash from "string-hash";
import { PMTiles } from "pmtiles";
import {Map, LayerSpecification, StyleSpecification, ValidationError, SourceSpecification} from 'maplibre-gl'
import {latest, validateStyleMin} from '@maplibre/maplibre-gl-style-spec'

Expand Down Expand Up @@ -638,33 +639,42 @@ export default class App extends React.Component<any, AppState> {
console.warn("Failed to setFetchAccessToken: ", err);
}

fetch(url!, {
mode: 'cors',
})
.then(response => response.json())
.then(json => {
const setVectorLayers = (json:any) => {
if(!Object.prototype.hasOwnProperty.call(json, "vector_layers")) {
return;
}

if(!Object.prototype.hasOwnProperty.call(json, "vector_layers")) {
return;
}
// Create new objects before setState
const sources = Object.assign({}, {
[key]: this.state.sources[key],
});

// Create new objects before setState
const sources = Object.assign({}, {
[key]: this.state.sources[key],
});
for(const layer of json.vector_layers) {
(sources[key] as any).layers.push(layer.id)
}

for(const layer of json.vector_layers) {
(sources[key] as any).layers.push(layer.id)
}
console.debug("Updating source: "+key);
this.setState({
sources: sources
});
};

console.debug("Updating source: "+key);
this.setState({
sources: sources
if (url!.startsWith("pmtiles://")) {
(new PMTiles(url!.substr(10))).getTileJson("")
.then(json => setVectorLayers(json))
.catch(err => {
console.error("Failed to process sources for '%s'", url, err);
});
} else {
fetch(url!, {
mode: 'cors',
})
.catch(err => {
console.error("Failed to process sources for '%s'", url, err);
});
.then(response => response.json())
.then(json => setVectorLayers(json))
.catch(err => {
console.error("Failed to process sources for '%s'", url, err);
});
}
}
else {
sourceList[key] = this.state.sources[key] || this.state.mapStyle.sources[key];
Expand Down
3 changes: 3 additions & 0 deletions src/components/MapMaplibreGl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import MaplibreGeocoder, { MaplibreGeocoderApi, MaplibreGeocoderApiConfig } from
import '@maplibre/maplibre-gl-geocoder/dist/maplibre-gl-geocoder.css';
import { withTranslation, WithTranslation } from 'react-i18next'
import i18next from 'i18next'
import { Protocol } from "pmtiles";

function renderPopup(popup: JSX.Element, mountNode: ReactDOM.Container): HTMLElement {
ReactDOM.render(popup, mountNode);
Expand Down Expand Up @@ -148,6 +149,8 @@ class MapMaplibreGlInternal extends React.Component<MapMaplibreGlInternalProps,
localIdeographFontFamily: false
} satisfies MapOptions;

let protocol = new Protocol({metadata: true});
MapLibreGl.addProtocol("pmtiles",protocol.tile);
const map = new MapLibreGl.Map(mapOpts);

const mapViewChange = () => {
Expand Down
6 changes: 6 additions & 0 deletions src/components/ModalSources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ function editorMode(source: SourceSpecification) {
}
if(source.type === 'vector') {
if(source.tiles) return 'tile_vector'
if(source.url?.startsWith("pmtiles://")) return 'pmtiles_vector'
return 'tilejson_vector'
}
if(source.type === 'geojson') {
Expand Down Expand Up @@ -129,6 +130,10 @@ class AddSource extends React.Component<AddSourceProps, AddSourceState> {
const {protocol} = window.location;

switch(mode) {
case 'pmtiles_vector': return {
type: 'vector',
url: `${protocol}//localhost:3000/file.pmtiles`
}
case 'geojson_url': return {
type: 'geojson',
data: `${protocol}//localhost:3000/geojson.json`
Expand Down Expand Up @@ -240,6 +245,7 @@ class AddSource extends React.Component<AddSourceProps, AddSourceState> {
['tile_raster', t('Raster (Tile URLs)')],
['tilejson_raster-dem', t('Raster DEM (TileJSON URL)')],
['tilexyz_raster-dem', t('Raster DEM (XYZ URLs)')],
['pmtiles_vector', 'Vector (PMTiles)'],
['image', t('Image')],
['video', t('Video')],
]}
Expand Down
29 changes: 28 additions & 1 deletion src/components/ModalSourcesTypeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import FieldCheckbox from './FieldCheckbox'
import { WithTranslation, withTranslation } from 'react-i18next';
import { TFunction } from 'i18next'

export type EditorMode = "video" | "image" | "tilejson_vector" | "tile_raster" | "tilejson_raster" | "tilexyz_raster-dem" | "tilejson_raster-dem" | "tile_vector" | "geojson_url" | "geojson_json" | null;
export type EditorMode = "video" | "image" | "tilejson_vector" | "tile_raster" | "tilejson_raster" | "tilexyz_raster-dem" | "tilejson_raster-dem" | "pmtiles_vector" | "tile_vector" | "geojson_url" | "geojson_json" | null;

type TileJSONSourceEditorProps = {
source: {
Expand Down Expand Up @@ -286,6 +286,32 @@ class GeoJSONSourceFieldJsonEditor extends React.Component<GeoJSONSourceFieldJso
}
}

type PMTilesSourceEditorProps = {
source: {
url: string
}
onChange(...args: unknown[]): unknown
children?: React.ReactNode
} & WithTranslation;

class PMTilesSourceEditor extends React.Component<PMTilesSourceEditorProps> {
render() {
const t = this.props.t;
return <div>
<FieldUrl
label={t("PMTiles URL")}
fieldSpec={latest.source_vector.url}
value={this.props.source.url}
onChange={url => this.props.onChange({
...this.props.source,
url: `pmtiles://${url}`
})}
/>
{this.props.children}
</div>
}
}

type ModalSourcesTypeEditorInternalProps = {
mode: EditorMode
source: any
Expand Down Expand Up @@ -343,6 +369,7 @@ class ModalSourcesTypeEditorInternal extends React.Component<ModalSourcesTypeEdi
value={this.props.source.encoding || latest.source_raster_dem.encoding.default}
/>
</TileURLSourceEditor>
case 'pmtiles_vector': return <PMTilesSourceEditor {...commonProps} />
case 'image': return <ImageSourceEditor {...commonProps} />
case 'video': return <VideoSourceEditor {...commonProps} />
default: return null
Expand Down

0 comments on commit 60ad65a

Please sign in to comment.