Skip to content

Commit

Permalink
Update MapLibre dependencies, add terrain editing (#859)
Browse files Browse the repository at this point in the history
This PR aims at updating MapLibre dependencies.

The main goal of this update is to allow adding terrain specification to
the editor.
This requires version 4 of maplibre so currently it will use the
pre-release.
  • Loading branch information
HarelM authored Jan 11, 2024
1 parent 87cf81d commit eb48bed
Show file tree
Hide file tree
Showing 20 changed files with 349 additions and 111 deletions.
4 changes: 2 additions & 2 deletions cypress/e2e/modals.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ describe("modals", () => {
when.click("nav:settings");
});

describe("when click name", () => {
describe("when click name filed spec information", () => {
beforeEach(() => {
when.click("field-doc-button-Name");
});

it("name", () => {
it("should show the spec information", () => {
then(get.elementsText("spec-field-doc")).shouldInclude(
"name for the style"
);
Expand Down
306 changes: 269 additions & 37 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"homepage": "https://github.com/maputnik/editor#readme",
"dependencies": {
"@mapbox/mapbox-gl-rtl-text": "^0.2.3",
"@maplibre/maplibre-gl-style-spec": "^17.0.1",
"@maplibre/maplibre-gl-style-spec": "^20.1.0",
"@mdi/js": "^6.6.96",
"@mdi/react": "^1.5.0",
"@typescript-eslint/eslint-plugin": "^6.16.0",
Expand All @@ -46,7 +46,7 @@
"lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1",
"mapbox-gl-inspect": "^1.3.1",
"maplibre-gl": "^2.4.0",
"maplibre-gl": "^4.0.0-pre.4",
"maputnik-design": "github:maputnik/design#172b06c",
"ol": "^6.14.1",
"ol-mapbox-style": "^7.1.1",
Expand Down
5 changes: 2 additions & 3 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {unset} from 'lodash'
import {arrayMoveMutable} from 'array-move'
import hash from "string-hash";
import {Map, LayerSpecification, StyleSpecification, ValidationError, SourceSpecification} from 'maplibre-gl'
import {latest, validate} from '@maplibre/maplibre-gl-style-spec'
import {latest, validateStyleMin} from '@maplibre/maplibre-gl-style-spec'

import MapMaplibreGl from './MapMaplibreGl'
import MapOpenLayers from './MapOpenLayers'
Expand Down Expand Up @@ -379,8 +379,7 @@ export default class App extends React.Component<any, AppState> {
this.getInitialStateFromUrl(newStyle);
}

// This "any" can be removed in latest version of maplibre where maplibre re-exported types from style-spec
const errors = validate(newStyle as any, latest) || [];
const errors: ValidationError[] = validateStyleMin(newStyle) || [];

// The validate function doesn't give us errors for duplicate error with
// empty string for layer.id, manually deal with that here.
Expand Down
2 changes: 1 addition & 1 deletion src/components/FieldId.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'

import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block'
import InputString from './InputString'

Expand Down
2 changes: 1 addition & 1 deletion src/components/FieldMaxZoom.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'

import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block'
import InputNumber from './InputNumber'

Expand Down
2 changes: 1 addition & 1 deletion src/components/FieldMinZoom.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'

import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block'
import InputNumber from './InputNumber'

Expand Down
2 changes: 1 addition & 1 deletion src/components/FieldSource.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'

import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block'
import InputAutocomplete from './InputAutocomplete'

Expand Down
2 changes: 1 addition & 1 deletion src/components/FieldType.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'

import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block'
import InputSelect from './InputSelect'
import InputString from './InputString'
Expand Down
2 changes: 1 addition & 1 deletion src/components/FilterEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function createStyleFromFilter(filter: LegacyFilterSpecification | ExpressionSpe
"sources": {
"tmp": {
"type": "geojson",
"data": {}
"data": ''
}
},
"sprite": "",
Expand Down
34 changes: 7 additions & 27 deletions src/components/MapMaplibreGl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ import 'maplibre-gl/dist/maplibre-gl.css'
import '../maplibregl.css'
import '../libs/maplibre-rtl'


const IS_SUPPORTED = MapLibreGl.supported();

function renderPopup(popup: JSX.Element, mountNode: ReactDOM.Container) {
ReactDOM.render(popup, mountNode);
return mountNode;
Expand Down Expand Up @@ -92,8 +89,6 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
}

updateMapFromProps(props: MapMaplibreGlProps) {
if(!IS_SUPPORTED) return;

if(!this.state.map) return

//Maplibre GL now does diffing natively so we don't need to calculate
Expand All @@ -115,8 +110,6 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
}

componentDidUpdate() {
if(!IS_SUPPORTED) return;

const map = this.state.map;

this.updateMapFromProps(this.props);
Expand Down Expand Up @@ -146,8 +139,6 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
}

componentDidMount() {
if(!IS_SUPPORTED) return;

const mapOpts = {
...this.props.options,
container: this.container!,
Expand Down Expand Up @@ -235,24 +226,13 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
}

render() {
if(IS_SUPPORTED) {
return <div
className="maputnik-map__map"
role="region"
aria-label="Map view"
ref={x => this.container = x}
data-wd-key="maplibre:map"
></div>
}
else {
return <div
className="maputnik-map maputnik-map--error"
>
<div className="maputnik-map__error-message">
Error: Cannot load MaplibreGL, WebGL is either unsupported or disabled
</div>
</div>
}
return <div
className="maputnik-map__map"
role="region"
aria-label="Map view"
ref={x => this.container = x}
data-wd-key="maplibre:map"
></div>
}
}

70 changes: 49 additions & 21 deletions src/components/ModalSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import type {LightSpecification, StyleSpecification, TransitionSpecification} from 'maplibre-gl'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import type {LightSpecification, StyleSpecification, TerrainSpecification, TransitionSpecification} from 'maplibre-gl'

import FieldArray from './FieldArray'
import FieldNumber from './FieldNumber'
Expand Down Expand Up @@ -58,6 +58,25 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
});
}

changeTerrainProperty(property: keyof TerrainSpecification, value: any) {
const terrain = {
...this.props.mapStyle.terrain,
}

if (value === undefined) {
delete terrain[property];
}
else {
// @ts-ignore
terrain[property] = value;
}

this.props.onStyleChanged({
...this.props.mapStyle,
terrain,
});
}

changeStyleProperty(property: keyof StyleSpecification | "owner", value: any) {
const changedStyle = {
...this.props.mapStyle,
Expand All @@ -77,10 +96,12 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
render() {
const metadata = this.props.mapStyle.metadata || {} as any;
const {onChangeMetadataProperty, mapStyle} = this.props;
const inputProps = { }

const light = this.props.mapStyle.light || {};
const transition = this.props.mapStyle.transition || {};
const terrain = this.props.mapStyle.terrain || {} as TerrainSpecification;

console.log(latest);

return <Modal
data-wd-key="modal:settings"
Expand All @@ -89,45 +110,45 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
title={'Style Settings'}
>
<div className="modal:settings">
<FieldString {...inputProps}
<FieldString
label={"Name"}
fieldSpec={latest.$root.name}
data-wd-key="modal:settings.name"
value={this.props.mapStyle.name}
onChange={this.changeStyleProperty.bind(this, "name")}
/>
<FieldString {...inputProps}
<FieldString
label={"Owner"}
fieldSpec={{doc: "Owner ID of the style. Used by Mapbox or future style APIs."}}
data-wd-key="modal:settings.owner"
value={(this.props.mapStyle as any).owner}
onChange={this.changeStyleProperty.bind(this, "owner")}
/>
<FieldUrl {...inputProps}
<FieldUrl
fieldSpec={latest.$root.sprite}
label="Sprite URL"
data-wd-key="modal:settings.sprite"
value={this.props.mapStyle.sprite as string}
onChange={this.changeStyleProperty.bind(this, "sprite")}
/>

<FieldUrl {...inputProps}
<FieldUrl
label="Glyphs URL"
fieldSpec={latest.$root.glyphs}
data-wd-key="modal:settings.glyphs"
value={this.props.mapStyle.glyphs as string}
onChange={this.changeStyleProperty.bind(this, "glyphs")}
/>

<FieldString {...inputProps}
<FieldString
label={fieldSpecAdditional.maputnik.maptiler_access_token.label}
fieldSpec={fieldSpecAdditional.maputnik.maptiler_access_token}
data-wd-key="modal:settings.maputnik:openmaptiles_access_token"
value={metadata['maputnik:openmaptiles_access_token']}
onChange={onChangeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
/>

<FieldString {...inputProps}
<FieldString
label={fieldSpecAdditional.maputnik.thunderforest_access_token.label}
fieldSpec={fieldSpecAdditional.maputnik.thunderforest_access_token}
data-wd-key="modal:settings.maputnik:thunderforest_access_token"
Expand All @@ -141,21 +162,19 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
length={2}
type="number"
value={mapStyle.center || []}
default={latest.$root.center.default || [0, 0]}
default={[0, 0]}
onChange={this.changeStyleProperty.bind(this, "center")}
/>

<FieldNumber
{...inputProps}
label={"Zoom"}
fieldSpec={latest.$root.zoom}
value={mapStyle.zoom}
default={latest.$root.zoom.default || 0}
default={0}
onChange={this.changeStyleProperty.bind(this, "zoom")}
/>

<FieldNumber
{...inputProps}
label={"Bearing"}
fieldSpec={latest.$root.bearing}
value={mapStyle.bearing}
Expand All @@ -164,7 +183,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>

<FieldNumber
{...inputProps}
label={"Pitch"}
fieldSpec={latest.$root.pitch}
value={mapStyle.pitch}
Expand All @@ -173,7 +191,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>

<FieldEnum
{...inputProps}
label={"Light anchor"}
fieldSpec={latest.light.anchor}
name="light-anchor"
Expand All @@ -184,7 +201,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>

<FieldColor
{...inputProps}
label={"Light color"}
fieldSpec={latest.light.color}
value={light.color as string}
Expand All @@ -193,7 +209,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>

<FieldNumber
{...inputProps}
label={"Light intensity"}
fieldSpec={latest.light.intensity}
value={light.intensity as number}
Expand All @@ -202,7 +217,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>

<FieldArray
{...inputProps}
label={"Light position"}
fieldSpec={latest.light.position}
type="number"
Expand All @@ -212,8 +226,23 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
onChange={this.changeLightProperty.bind(this, "position")}
/>

<FieldString
label={"Terrain source"}
fieldSpec={latest.terrain.source}
data-wd-key="modal:settings.maputnik:terrain_source"
value={terrain.source}
onChange={this.changeTerrainProperty.bind(this, "source")}
/>

<FieldNumber
label={"Terrain exaggeration"}
fieldSpec={latest.terrain.exaggeration}
value={terrain.exaggeration}
default={latest.terrain.exaggeration.default}
onChange={this.changeTerrainProperty.bind(this, "exaggeration")}
/>

<FieldNumber
{...inputProps}
label={"Transition delay"}
fieldSpec={latest.transition.delay}
value={transition.delay}
Expand All @@ -222,15 +251,14 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>

<FieldNumber
{...inputProps}
label={"Transition duration"}
fieldSpec={latest.transition.duration}
value={transition.duration}
default={latest.transition.duration.default}
onChange={this.changeTransitionProperty.bind(this, "duration")}
/>

<FieldSelect {...inputProps}
<FieldSelect
label={fieldSpecAdditional.maputnik.style_renderer.label}
fieldSpec={fieldSpecAdditional.maputnik.style_renderer}
data-wd-key="modal:settings.maputnik:renderer"
Expand Down
4 changes: 2 additions & 2 deletions src/components/ModalSources.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import {MdAddCircleOutline, MdDelete} from 'react-icons/md'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import type {GeoJSONSourceSpecification, RasterDEMSourceSpecification, RasterSourceSpecification, SourceSpecification, StyleSpecification, VectorSourceSpecification} from 'maplibre-gl'

import Modal from './Modal'
Expand Down Expand Up @@ -134,7 +134,7 @@ class AddSource extends React.Component<AddSourceProps, AddSourceState> {
case 'geojson_json': return {
type: 'geojson',
cluster: (source as GeoJSONSourceSpecification).cluster || false,
data: {}
data: ''
}
case 'tilejson_vector': return {
type: 'vector',
Expand Down
Loading

0 comments on commit eb48bed

Please sign in to comment.