Giter Site home page Giter Site logo

geoblocks / ol-maplibre-layer Goto Github PK

View Code? Open in Web Editor NEW
29.0 5.0 5.0 16.19 MB

Use a MapBox map as an OpenLayers layer

Home Page: https://geoblocks.github.io/ol-maplibre-layer/demo.html

License: BSD 3-Clause "New" or "Revised" License

TypeScript 100.00%
maplibre openlayers

ol-maplibre-layer's Introduction

Geoblocks

Description

Geoblocks are pieces of code:

  • with minimal dependencies choosing versions;
  • independant;
  • easy to use;
  • tested and documented testing;
  • maintained by the people who use them;
  • written in plain ES6 or typescript;
  • distributed as ES6 modules + typescript d.ts typing.

Github / Npm

Each block is maintained in its own independant github repository in the github geoblocks organisation.

Blocks are published on npm in the npm geoblocks organisation.

Usage

The proj block exposes OpenLayers projections. To use them:

  • npm i --save @geoblocks/proj
  • import EPSG_2056 from '@geoblocks/proj/src/EPSG_2056.js';
  • you are done!

Contributing

  • Create issue / PR in the block;
  • A block maintainer will review and merge;
  • To create new blocks get in touch with us.

Choosing dependency versions

Each block has a package.json file specifying the dependencies of the block. For each dependency, the block author must specify a range starting at the smallest usable version.

Let's take an example. The proj block depends on OpenLayers 5. It is usable with all the versions in the range [5.3.0, current] so the package.json file must contain:

ol": ">=5.3.0",

During the CI tests, both version 5.3.0 and the latest version are tested. Here is how it is handled.

Typing

Blocks can be written as plain ES6 modules. But to catch errors early and to benefit from modern Javascript editing in code editors like VSCode, it is required to:

  • publish typescript definition files (d.ts);
  • define typescript interfaces when implementing a generic feature.

With proper annotations, note that plain ES6 modules blocks can use typescript as a typechecker.

Testing

  • enable CI with tests and coverage example with JEST;
  • publish a documentation;
  • eventually publish examples.

See the sources block.

ol-maplibre-layer's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar fredj avatar gberaudo avatar ger-benjamin avatar renovate[bot] avatar taulinger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ol-maplibre-layer's Issues

Use custom pbf tiles and styles

Is it possible to use custom pbf vector tiles and styles? We have them located at:

  • tiles: /tiles/12/2127/1372.pbf
  • styles: /styles/highContrast_campusGIS.json

Map window loading the side

First, I wanted to say thank you for this great tool. I really like the idea of bring together maplibre and Openlayers.

I am trying to drill down if this is a bug in geoblocks, openlayers, or in my code. Maybe you have seen this, but I am getting curious behaviour when a vector tile map from ol-maplibre-layer initially loads into the map container from openlayers.

I am running the following with no issue:

const osmSource = new OSM();

window.map = new Map({
  layers: [
    new MapLibreLayer({
      maplibreOptions: {
        style: './style.json',
      },
      source: new Source({
        attributions: [
          '<a href="https://www.geo.admin.ch/en/geo-services/geo-services/portrayal-services-web-mapping/vector_tiles_service.html" target="_blank">© swisstopo</a>',
        ],
      }),
    }),
    new TileLayer({
      source: new TileDebug({
        projection: 'EPSG:3857',
        tileGrid: osmSource.getTileGrid()
      })
    })
  ],
  target: 'map',
  view: new View({
    center: olProj.fromLonLat([174.0,-41.29]),
    zoom: 8
  })
});

With Grid
Screenshot from 2022-03-24 18-26-16

However, if the remove the OSM tile grid, the map initially loads in the in the top left corner of the window. If I zoom in any direction the map fills the window just fine. So, remove OSM tilegrid

const osmSource = new OSM();

window.map = new Map({
  layers: [
    new MapLibreLayer({
      maplibreOptions: {
        style: './style.json',
      },
      source: new Source({
        attributions: [
          '<a href="https://www.geo.admin.ch/en/geo-services/geo-services/portrayal-services-web-mapping/vector_tiles_service.html" target="_blank">© swisstopo</a>',
        ],
      }),
    }),
    ],
  target: 'map',
  view: new View({
    center: olProj.fromLonLat([174.0,-41.29]),
    zoom: 8
  })
});

and I get this:
Screenshot from 2022-03-24 18-25-48

If I touch the map to zoom, everything is fine
Screenshot from 2022-03-24 18-27-03

It seems like the map window needs to initialize with a layer other than the maplibre layer to set correctly. I have tried load other non-maplibre layers along with the libre layer and get the same results.

If this is not a bug, maybe you have an idea where I could look to solve this?

Load/destroy the maplibre map only when visible/hidden and allow map.getFeaturesAtPixel

Hi @fredj ,

Inspired by this project we have developed our own MaplibreLayer in mobility-toolbox-js ,for the v3 we have switched to a complete renderer class instead of the use of the render function, it allows us to use the map.getFeaturesAtPixel function.

So the difference between ol-maplibre-layer and mobility-toolbox-js:

  • load the malibre map only when visible
  • automatically update attributions when source data changes
  • relaod the maplibre map on target change event
  • allow the use of map.getFeaturesAtPixel to get vector tiles features as OpenLayer feature

Since I don't like duplicated code, we would be happy to propose a PR for those improvements. Are you interested in ?

Here is a demo

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • chore(deps): lock file maintenance

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/ci.yml
  • actions/checkout v4
  • ubuntu 22.04
npm
package.json
  • @parcel/packager-ts 2.12.0
  • @parcel/transformer-typescript-types 2.12.0
  • @typescript-eslint/eslint-plugin 7.6.0
  • @typescript-eslint/parser 7.6.0
  • eslint 8.57.0
  • eslint-config-prettier 9.1.0
  • gh-pages 6.1.1
  • maplibre-gl 4.1.2
  • ol 9.1.0
  • parcel 2.12.0
  • prettier 3.2.5
  • typescript 5.4.4
  • maplibre-gl >=2.0.4
  • ol >=6.10

  • Check this box to trigger a request for Renovate to run again on this repository

Any usage with Mapbox

Hello,

Thank you for your lib that I use as a snippet for Mapbox.
But I'm facing a wrong (or unwanted) behavior while panning the map.

With MapLibre, while panning the map, every feature of OpenLayers are following and are synchronized with MapLibre.
However, with Mapbox, is not true. There is a delay that makes the map still smooth but unsynchronized.

I would like to know if you, here, have a solution already?
A solution that forces features, tiles and so to follow each other.

I tested by overriding the panning function of Mapbox, but without success.

Here, you can find what I use (from your lib) :

import Layer from 'ol/layer/Layer';
import { toDegrees } from 'ol/math';
import { toLonLat } from 'ol/proj';
import mapbox from 'mapbox-gl';
import type { FrameState } from 'ol/Map';
import type { Options as LayerOptions } from 'ol/layer/Layer';
import 'mapbox-gl/dist/mapbox-gl.css';
import { sameSize } from './utils';

type MapBoxLayerOptions = LayerOptions & {
  mapboxOptions: Omit<mapbox.MapboxOptions, 'container'>;
};

/**
 * Display a Mapbox map as an OpenLayers layer.
 * Heavily inspired by : https://github.com/geoblocks/ol-maplibre-layer.
 * Few changes to "use as is" with Mapbox instead of MapLibre.
 */
export default class MapBoxLayer extends Layer {
  mapboxMap: mapbox.Map;

  constructor(options: MapBoxLayerOptions) {
    const { mapboxOptions, ...baseOptions } = options;

    super(baseOptions);

    const container = document.createElement('div');

    container.style.position = 'absolute';
    container.style.width = '100%';
    container.style.height = '100%';
    container.style.top = '0';
    container.style.left = '0';
    container.style.bottom = '0';

    this.mapboxMap = new mapbox.Map({
      attributionControl: false,
      interactive: false,
      trackResize: false,
      clickTolerance: 0,
      keyboard: false,
      pitchWithRotate: false,
      doubleClickZoom: false,
      dragPan: false,
      dragRotate: false,
      touchZoomRotate: false,
      touchPitch: false,
      boxZoom: false,
      renderWorldCopies: false,
      preserveDrawingBuffer: false,
      antialias: false,
      fadeDuration: 300,
      optimizeForTerrain: true,
      crossSourceCollisions: false,
      ...mapboxOptions,
      container,
    });

    this.applyOpacity();
  }

  override disposeInternal() {
    this.mapboxMap.remove();
    super.disposeInternal();
  }

  override setOpacity(opacity: number) {
    super.setOpacity(opacity);
    this.applyOpacity();
  }

  private applyOpacity() {
    const canvas = this.mapboxMap.getCanvas();
    const opacity = this.getOpacity().toString();

    if (opacity !== canvas.style.opacity) {
      canvas.style.opacity = opacity;
    }
  }

  override render(frameState: FrameState): HTMLElement {
    const { viewState } = frameState;

    this.mapboxMap.jumpTo({
      center: toLonLat(viewState.center) as [number, number],
      zoom: viewState.zoom - 1,
      bearing: toDegrees(-viewState.rotation),
    });

    const mapboxCanvas = this.mapboxMap.getCanvas();

    if (!mapboxCanvas.isConnected) {
      this.getMapInternal()?.render();
    } else if (!sameSize(mapboxCanvas, frameState)) {
      this.mapboxMap.resize();
    }

    this.mapboxMap.triggerRepaint();

    return this.mapboxMap.getContainer();
  }
}

Thank you for your lib!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.