Skip to content

Commit

Permalink
bundle maplibre-layers statically as a mapbox wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
mki-c2c committed Aug 18, 2023
1 parent faf477e commit 88a2618
Show file tree
Hide file tree
Showing 9 changed files with 57,134 additions and 32,116 deletions.
29,940 changes: 14,227 additions & 15,713 deletions bundle/lux.dist.mjs

Large diffs are not rendered by default.

29,943 changes: 14,228 additions & 15,715 deletions bundle/lux.dist.umd.js

Large diffs are not rendered by default.

28,478 changes: 28,477 additions & 1 deletion bundle/style.css

Large diffs are not rendered by default.

717 changes: 113 additions & 604 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"dependencies": {
"@camptocamp/ogc-client": "^0.3.4",
"file-saver": "^2.0.5",
"maplibre-gl": "^3.2.2",
"mapbox-gl": "^1.7.0",
"ol": "^6.5.0",
"pinia": "^2.0.26",
"sortablejs": "^1.15.0",
Expand Down
14 changes: 13 additions & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { onMounted, onUnmounted, watch } from 'vue'
import { storeToRefs } from 'pinia'
import MapLibreLayer from '@/lib/ol-maplibre-layer'
import olLayerGroup from 'ol/layer/Group.js'
import { MapLibreLayerType } from './composables/map/map.model'
import HeaderBar from './components/header/header-bar.vue'
Expand Down Expand Up @@ -44,6 +45,15 @@ watch(layersOpen, () =>
onMounted(() => window.addEventListener('resize', resizeMap))
onUnmounted(() => window.removeEventListener('resize', resizeMap))
function traverseLayer(layer, ancestors, visitor) {
const descend = visitor(layer, ancestors)
if (descend && layer instanceof olLayerGroup) {
layer.getLayers().forEach(childLayer => {
traverseLayer(childLayer, [...ancestors, layer], visitor)
})
}
}
function resizeMap() {
// Update all canvas size when layer panel is opened/closed
const map = useMap().getOlMap()
Expand All @@ -52,10 +62,12 @@ function resizeMap() {
map.updateSize()
// And trigger update MapLibre layers' canvas size
map.getAllLayers().forEach(layer => {
// map.getAllLayers().forEach(layer => {
traverseLayer(map.getLayerGroup(), [], layer => {
if (layer instanceof MapLibreLayer) {
;(layer as MapLibreLayerType).maplibreMap.resize()
}
return true
})
// TODO: Add slide effect and do this update after slide animation ends
Expand Down
2 changes: 2 additions & 0 deletions src/bundle/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import FooterBar from '@/components/footer/footer-bar.vue'
import LayerPanel from '@/components/layer-panel/layer-panel.vue'
import SliderComparator from '@/components/slider/slider-comparator.vue'
import useMap from '@/composables/map/map.composable'
import useOpenLayers from '@/composables/map/ol.composable'
import { useAppStore } from '@/stores/app.store'
import { useMapStore } from '@/stores/map.store'
import { useThemeStore } from '@/stores/config.store'
Expand Down Expand Up @@ -94,6 +95,7 @@ export {
LayerPanel,
SliderComparator,
useMap,
useOpenLayers,
useAppStore,
useMapStore,
useThemeStore,
Expand Down
1 change: 0 additions & 1 deletion src/composables/map/ol.composable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ function createVectorLayer(
const options = Object.assign(
{
container: mapService.getOlMap().getTarget(),
map: mapService.getOlMap(),
},
styleSource
)
Expand Down
153 changes: 73 additions & 80 deletions src/lib/ol-maplibre-layer.js
Original file line number Diff line number Diff line change
@@ -1,124 +1,117 @@
import Layer from 'ol/layer/Layer'
import { toDegrees } from 'ol/math'
import { toLonLat } from 'ol/proj'
import { toLonLat } from 'ol/proj.js'

import maplibregl from 'maplibre-gl'
import mapboxgl from 'mapbox-gl'

/**
* @typedef {Object} Options
* @property {Object<string, *>} maplibreOptions
* @property {string} [accessToken]
* @property {string} style
* @property {string|HTMLElement} container
*/

export default class MapLibreLayer extends Layer {
export default class MapBox extends Layer {
/**
* @param {Options} options
*/
constructor(options) {
const baseOptions = Object.assign({}, options)

delete baseOptions.maplibreOptions
// baseOptions.xyz = options.maplibreOptions.xyz
// baseOptions.xyz_custom = options.maplibreOptions.xyz_custom
delete baseOptions.accessToken
delete baseOptions.style
delete baseOptions.container
delete baseOptions.xyz

super(baseOptions)

// write directly to properties
this.set('xyz', options.maplibreOptions.xyz)
this.set('xyz_custom', options.maplibreOptions.xyz_custom)

// const container = options.maplibreOptions.container
this.map_ = options.maplibreOptions.map

const container = document.createElement('div')
container.style.width = '100%'
container.style.height = '100%'
container.style.position = 'absolute'
container.style.zIndex = -50
this.map_.getTarget().parentElement.appendChild(container)

this.maplibreMap = new maplibregl.Map(
Object.assign({}, options.maplibreOptions, {
container: container,
attributionControl: false,
interactive: false,
trackResize: false,
})
)
this.xyz_ = options.xyz

if (options.accessToken) {
mapboxgl.accessToken = options.accessToken
}

this.applyOpacity_()
this.map_ = new mapboxgl.Map({
container: options.maplibreOptions.container,
style: options.maplibreOptions.style,
attributionControl: false,
interactive: false,
})
this.maplibreMap = this.map_
}

/**
* @param {number} opacity
*/
setOpacity(opacity) {
super.setOpacity(opacity)
this.applyOpacity_()
getMapBoxMap() {
return this.map_
}

applyOpacity_() {
const canvas = this.maplibreMap.getCanvas()
const opacity = this.getOpacity().toString()
if (opacity !== canvas.style.opacity) {
canvas.style.opacity = opacity
}
getMapLibreMap() {
return this.map_
}

/**
* @param {import('ol/Map').FrameState} frameState
* @return {HTMLCanvasElement} canvas
* @param {import('ol/PluggableMap').FrameState} frameState
*/
render(frameState) {
const canvas = this.maplibreMap.getCanvas()
const canvas = this.map_.getCanvas()
const viewState = frameState.viewState

// adjust view parameters in maplibre
this.maplibreMap.jumpTo({
canvas.style.position = 'absolute'

const visible = this.getVisible()
canvas.style.display = visible ? 'block' : 'none'

const opacity = this.getOpacity().toString()
if (opacity !== canvas.style.opacity) {
canvas.style.opacity = opacity
}

// adjust view parameters in mapbox
const rotation = viewState.rotation
if (rotation) {
this.map_.rotateTo(toDegrees(-rotation), {
animate: false,
})
}
this.map_.jumpTo({
center: toLonLat(viewState.center),
zoom: viewState.zoom - 1,
bearing: toDegrees(-viewState.rotation),
animate: false,
})

const maplibreCanvas = this.maplibreMap.getCanvas()
if (!maplibreCanvas.isConnected) {
// The canvas is not connected to the DOM, request a map rendering at the next animation frame
// to set the canvas size.
this.map_.render()
// this.getMapInternal().render();
} else if (!sameSize(maplibreCanvas, frameState)) {
this.maplibreMap._container.style.width = `${frameState.size[0]}px`
this.maplibreMap._container.style.height = `${frameState.size[1]}px`
this.maplibreMap._container.style.position = 'absolute'
this.maplibreMap.resize()
this.maplibreMap._container.style.position = 'absolute'
// this.maplibreMap._container.style.display = 'none'
// cancel the scheduled update & trigger synchronous redraw
// see https://github.com/mapbox/mapbox-gl-js/issues/7893#issue-408992184
// NOTE: THIS MIGHT BREAK WHEN UPDATING MAPBOX
if (this.map_._frame) {
this.map_._frame.cancel()
this.map_._frame = null
}
this.map_._render()

// this.maplibreMap.redraw();
// if (this.maplibreMap._frame) {
// this.maplibreMap._frame.cancel()
// this.maplibreMap._frame = null
// }
// this.maplibreMap._render()

// return this.maplibreMap.getContainer();
return canvas
}

/**
* @param {string} name
* @param {boolean} visible
*/
setLayerVisibility(name, visible) {
this.map_.setLayoutProperty(
name,
'visibility',
visible ? 'visible' : 'none'
)
}

/**
* @return {mapboxgl.Style}
*/
getStyle() {
return this.map_.getStyle()
}

getXYZ() {
return this.get('xyz')
}
}

/**
*
* @param {HTMLCanvasElement} canvas
* @param {import('ol/Map').FrameState} frameState
* @return boolean
*/
function sameSize(canvas, frameState) {
return (
canvas.width === Math.floor(frameState.size[0] * frameState.pixelRatio) ||
canvas.height === Math.floor(frameState.size[1] * frameState.pixelRatio)
)
}

0 comments on commit 88a2618

Please sign in to comment.