Giter Club home page Giter Club logo

vue-mapbox-gl's Introduction

πŸ—Ί Vue 3 Mapbox GL

NPM Version

A small components library to use Mapbox GL in Vue 3 app.

Installation & usage

Have a look at the small guide for information on how to setup a simple map.

Components

The following components are available:

Component Description Doc.
MapboxMap Display a map with the given style. βœ…
MapboxMarker Display a simple or custom marker. βœ…
MapboxCluster Display a GeoJSON as clusters. βœ…
MapboxGeocoder Display a geocoder search input with the @mapbox/mapbox-gl-geocoder plugin. βœ…
MapboxImage Load an image to be used on the map. βœ…
MapboxImages Load multiple images to be used on the map. βœ…
MapboxLayer Display a layer on the map. ❌
MapboxNavigationControl Display the map's navigation controls βœ…
MapboxPopup Display a popup on the map βœ…
MapboxSource Load a source of data to be used on the map ❌

Contributing

Installation

# Clone the project
git clone [email protected]:studiometa/vue-mapbox-gl.git
# Cd in the repository
cd vue-mapbox-gl
# Install dependencies
npm i

Useful commands

# Build for deployment
npm run build
# Test before deployment
npm run test
# Lint files
npm run lint
# Fix linting errors
npm run fix

Note

This project is a rewrite of a fork of openearth/vue2mapbox-gl and is published under the GNU GPL 3 license.

vue-mapbox-gl's People

Contributors

asanmiguel-nodrizatech avatar dependabot[bot] avatar depfu[bot] avatar einardivision avatar guizmo51 avatar kayrunm avatar keziahmoselle avatar michaelklopf avatar perruche avatar renovate-bot avatar titouanmathis avatar tmlmt 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  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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-mapbox-gl's Issues

Vue 3 compatibilty

Hi,
is the library already compatible with Vue 3 ?
If not, are there any plans on supporting Vue 3 ?
Thanks !

MapboxGeolocateControl not exported into build

Hello,
the new MapboxGeolocateControl is not exported from the src/components/index.js file, so it is not available in the last build (1.3.1). I don't know enough Vuepress to understand why the demo is working,

Btw, thanks for all the updates you made these last days !

Duplicate source ID for mulitple cluster

I'm getting the following error:

Error: There is already a source with this ID

When I'm using two MapboxCluster

 <MapboxMap
          map-style="mapbox://styles/mapbox/streets-v11"
          style="height: 100%"
          access-token="pk.eyJ1IjoicmFmbnVzcyIsImEiOiIzMVE1dnc0In0.3FNMKIlQ_afYktqki-6m0g"
          @mb-created="(mapInstance) => (map = mapInstance)"
        >
          <MapboxCluster
            :data="myLocationGeojson"
          />
          <MapboxCluster
            :data="hotspotGeojson"
          />
        </MapboxMap>

The id seems to be "mb-cluster-0-source" for both MapboxSource created.
Is there a way to define this id at construction?

Draggend

Good day,

Is there a way to access the marker location after draggend? I get the event to trigger with the below code, but can't seem to access the markers new location. I have access to the current location via Vue dev tools but it is set according to my manual geo or my address geocode lat lng.

@mb-dragend='markerMoved'

const markerMoved = () => {
console.log('moved');
}

Add the missing clusterProperties to clusters

This one is simple. It looks like clusterProperties got missed when implementing the props. I've forked this locally and modified the compiled code but do not have access to the individual components. So, here is my suggestion:

In vue-mapbox-gl/components/MapboxCluster.vue, add this new prop:

clusterProperties: {
		type: Object,
		default: null,
},

In the MapboxCluster setup function, I had to also extract and return the newly added prop, like this:

const { data, clusterMaxZoom, clusterRadius, clusterProperties, } = props;
return {
	type: "geojson",
	cluster: true,
	data,
	clusterMaxZoom,
	clusterRadius,
	clusterProperties,
};

Vue may handle this automatically, I'm not sure.

Thats it. Now, we can set custom properties to use in our cluster styling. I used this to color clusters differently based on if one of the markers inside has an "alert" tied to it.

Display better errors when components aren't wrapped in <mapbox-map>

This could be usefull to have better error display, especially since all mapbox child components are supposed to be use inside the mapbox-map component :

This exemple

<mapbox-map>
</mapbox-map>
<mapbox-marker>
</mapbox-marker>

will through TypeError: "this.$map is not a function", referencing the injectMap mixin

A type error like : "Make sure all your mapbox components are wrapped inside a " could be easier to understand.

Dependency Dashboard

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

Pending Approval

These branches will be created by Renovate only once you click their checkbox below.

  • Update actions/checkout action to v4
  • Update actions/setup-node action to v4
  • Update dependency @studiometa/eslint-config to v4
  • Update dependency @studiometa/prettier-config to v4
  • Update dependency eslint to v9
  • Update dependency prettier to v3
  • Update dependency unplugin-vue to v5
  • πŸ” Create all pending approval PRs at once πŸ”

Awaiting Schedule

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

  • Update dependency @studiometa/js-toolkit to v2.12.1
  • Update dependency vue to v3.4.34
  • Lock file maintenance

Pending Status Checks

These updates await pending status checks. To force their creation now, click the checkbox below.

  • Update dependency tailwindcss to v3.4.7

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/release.yml
  • actions/checkout v2
  • actions/setup-node v2
  • actions/create-release v1
.github/workflows/tests.yml
  • actions/checkout v2
  • actions/setup-node v2
  • actions/checkout v2
  • actions/setup-node v2
  • actions/checkout v2
npm
package.json
  • esbuild ^0.21.0
  • unplugin-vue ^4.1.0
  • @studiometa/eslint-config 3.1.3
  • @studiometa/prettier-config 2.1.1
  • eslint 8.57.0
  • prettier 2.8.8
packages/demo/package.json
  • @mapbox/mapbox-gl-geocoder ^5.0.2
  • mapbox-gl ^3.1.2
  • nuxt ^3.10.3
  • vue ^3.4.19
packages/docs/package.json
  • sass 1.77.8
  • tailwindcss 3.4.6
  • vitepress 1.3.1
packages/vue-mapbox-gl/package.json
  • @mapbox/mapbox-gl-geocoder 5.0.2
  • @studiometa/js-toolkit 2.12.0
  • mapbox-gl 3.5.2
  • vue 3.4.32
  • @mapbox/mapbox-gl-geocoder ^5.0.1
  • mapbox-gl ^2.8.2 || ^3.0.0
  • vue ^3.2.37
nvm
.nvmrc
  • node 20

MapboxCluster: `id`s of layer and source

Hey @titouanmathis, is there any reason why you don't allow for a custom id and auto generate ones with add an incremental index, for the 4 components included in a cluster (source, clusters layer, cluster-point layer unclustered layer)?

const id = ref(`mb-cluster-${index}`);
index += 1;
const getId = (suffix) => `${unref(id)}-${suffix}`;

I've noticed some issues when sometimes (haven't figured out when), the index ends up different from 0. Would it be possible to add a prop so that one can set a specific prefix? I can help with a PR if that can help.

DEP0151 DeprecationWarning

ERROR  (node:72455) [DEP0151] DeprecationWarning: No "main" or "exports" field defined in the package.json for /home/tmlmt/myproject/node_modules/@studiometa/vue-mapbox-gl/ resolving the main entry point "index.js", imported from /home/tmlmt/myproject/node_modules.
Default "index" lookups for the main are deprecated for ES modules.
(Use `node --trace-deprecation ...` to show where the warning was created)

Custom markers icon

Hi,

I read the doc but can't find how to customize markers icon.
I first tried with the MapboxImage component but impossible to link the id with the MapboxMarker component.
I then tried to pass a custom element props in MapboxMarker component but all my markers appeared stacked in one place (I have a v-for in MapboxMarker component to set lng-lat props).

Do you please have some working exemples ?

Best regards

The map is not zooming on the new bounds when a default center is given

We have a problem that when given a default center, that fitBounds does not zoom to the area with the given bounds and the new center of those bounds.

We set up the map according to the docs

    <MapboxMap 
         :access-token="token" 
         :center="[10.16493, 50.00602]" 
         :zoom="6" 
         map-style="mapbox://styles/mapbox/streets-v11" 
         @mb-created="(mapboxInstance) => map = mapboxInstance" 
         @mb-load="adjustBounds"
    >
        <MapboxMarker v-for="place in places" :key="place" :lng-lat="[place.longitude, place.latitude]" />
    </MapboxMap>

This is the code that should fit the map to the new bounds

const map = ref();

watch(
    () => props.places,
    () => {
        adjustBounds();
    }
);

const adjustBounds = () => {
    if (props.places.length === 0) {
        return;
    }

    let bounds = new Mapbox.LngLatBounds();

    for (const place of props.places) {
        bounds.extend([place.longitude, place.latitude]);
    }

    map.value.fitBounds(bounds, {
        padding: 50,
        duration: 3000,
    });
};

We debugged a little and the fitBounds function returns a new map object but with the default center set above, not with the new one internally computed. The nw and se boundaries of the map are new, but the center is not. Hence the map is showing the markers in a section of the map, but it stays focused on the default center and doesn't zoom.

Has anyone an example how he adjust the bounds with a given set of places returned form a search?

Cannot read properties of undefined (reading 'addTo')

This is my code. I'm getting this error. Cannot read properties of undefined (reading 'addTo')

<template>

            <MapboxGeocoder 
              :access-token="mapbox_token"
              :types="'address'"
              :country="'us'"
              :proximity="[-122.3995752 , 37.7881856]"
              map-style="mapbox://styles/mapbox/streets-v11"
              @mb-created="instance => control = instance"
              @mb-result="addAddress($event)"/>
 
</template>


<script>

    import { ref } from 'vue'
    import { MapboxMap, MapboxGeocoder } from '@studiometa/vue-mapbox-gl';
    import '@mapbox/mapbox-gl-geocoder/lib/mapbox-gl-geocoder.css';
   

    export default {
    
    components: {
        MapboxMap,
        MapboxGeocoder
    },
    props: {
      
    },
    emits: [
        'AddressSelected'
    ],  
    setup(props, {emit}){
        const control = ref();
        const mapbox_token = process.env.MIX_MAPBOX_SECRET
        const addAddress = (data) => { 
            emit('AddressSelected', data.result)
        }

        return{
            mapbox_token,
            control,
            addAddress
        }
    },

    }

    </script>

get data from selected autocomplete MapboxGeocoder

<template>
  <mapbox-geocoder :access-token="accesstoken"
   @mb-results="onComplete" 
   />
</template>

<script>
//import mapboxgl from 'mapbox-gl';
import { MapboxGeocoder } from '@studiometa/vue-mapbox-gl';
import "@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css";
export default {
  name: "geocoder",
  components: {
  //  mapboxgl,
 MapboxGeocoder
  },

  data() {
    return {
       types: "country,region,place,postcode,locality,neighborhood,address,poi", 
      accesstoken: "xxx.xxx.xxx",
      
    };
  },
  methods: {
    onComplete(response) {
      console.log(response)
    },
  },
};
</script>

Allow to prevent default behavior on cluster click

In the MapboxCluster component, there is the click handler function, this function moves the view to match the zoom level and the center of the clustered point.

My problem is that I want to avoid that behavior when I am drawing on some other layer, right now that is not possible because even I have defaultPrevented the event that the param is not taking on account before the view's movement.

Is there any workaround to this problem?

StoreLocator component improvements

  • Sort the items in the listing by their distance to the center of the map
  • Add an option to disable/enable automatic filtering of the items in view (Γ  la Airbnb)
  • Pass the filterFeaturesInView method as a slot props in each slot to allow using it on demand
  • Add a props to pass an initial search query string to the MapboxGeocoder component
  • Separate each parts of the store locator into multiple components for easier composition

Add an exemple on how to load a custom marker image for the StoreLocator component

Add a section on the documentation on "how to load a custom marker image for the StoreLocator component"

Add the important details:

  • image must be png
  • Adapt icon-size param if you load a png in size 2x or 3x
  • icon-image param must use the same name as in addImage fn

Code:

<template>
    <store-locator
      :items="items"
      :mapbox-cluster="{
        'unclustered-point-layer-type': 'circle',
        'unclustered-point-layer-type': 'symbol',
        'unclustered-point-layout': {
          'icon-image': 'pin',
          'icon-size': 1
        },
        'unclustered-point-paint': {},
      }"
      access-token="..."
      :mapbox-map="{
        mapStyle: '...',
        center: [ 2.0, 48.0 ],
        zoom: 1,
      }"
      @map-created="onMapCreated">
      <!-- template -->
    </store-locator>
</template>

<script>
  export default {
    props: {
      items: {
        type: Array,
        required: true,
      },
   },
    methods: {
      onMapCreated(map) {
       const imgPath = 'imag.png';
        map.loadImage(imagePath, (error, image) => {
          if (error) { throw error; }
          map.addImage('pin', image);
        });
      },
    },
  };
</script>

TypeScript: `index.d.ts` file?

First of all, thanks for this project πŸ‘πŸ»

Map is working.

But when I do type check with nuxi typecheck command I get:

Π‘Π½ΠΈΠΌΠΎΠΊ экрана 2023-05-27 Π² 14 33 52
    "vue-tsc": "1.6.5"

Installing these deps did not help:

{
"@types/mapbox__mapbox-gl-geocoder": "^4.7.3",
 "@types/mapbox-gl": "^2.7.11"
}

Solved it by adding into shims.d.ts file:

declare module '@studiometa/vue-mapbox-gl' {
    export const MapboxMap: any;
    export const MapboxMarker: any;
    export const MapboxCluster: any;
    export const MapboxGeocoder: any;
    export const MapboxGeolocateControl: any;
    export const MapboxImage: any;
    export const MapboxImages: any;
    export const MapboxLayer: any;
    export const MapboxNavigationControl: any;
    export const MapboxPopup: any;
    export const MapboxSource: any;
    export const StoreLocator: any;
}

Could index.d.ts be added to library?

Documentation is unclear about the installation of @mapbox/mapbox-gl-geocoder

I get the following error, when I install the package without the @mapbox/mapbox-gl-geocoder.

✘ [ERROR] Could not resolve "@mapbox/mapbox-gl-geocoder"

    ../../node_modules/@studiometa/vue-mapbox-gl/index.js:580:27:
      580 β”‚ import MapboxGeocoder from "@mapbox/mapbox-gl-geocoder";
          β•΅                            ~~~~~~~~~~~~~~~~~~~~~~~~~~

  You can mark the path "@mapbox/mapbox-gl-geocoder" as external to exclude it from the bundle,
  which will remove this error.

The documentation suggests the installation is optional, see here https://vue-mapbox-gl.studiometa.dev/guide/installation/

# The geocoder package is only required if you use the `MapboxGeocoder` component
npm install @mapbox/mapbox-gl-geocoder

The code does require the package though. So who is correct?

Setting cooperativeGestures on MapboxMap

Cooperative Gestures and perhaps some other newer options are missing from the MapboxMap props declarations. Could this be added or perhaps allow the developer to pass any options they like to reduce work on your side?

Thanks

Mapbox Cluster

did not find an example of a custom Mapbox Cluster, is it possible to do this?

Error component MapboxGeocoder

The component MapboxGeocoder work but i have this error in my console when i use it :

TypeError: Cannot set properties of undefined (setting '_eventEmitter')
    at MapboxGeocoder

I don't know if the error comes from my code or the component itself

my code :

import { MapboxMap, MapboxImage, MapboxCluster, MapboxPopup } from '@studiometa/vue-mapbox-gl'
import 'mapbox-gl/dist/mapbox-gl.css'
import axios from 'redaxios'
import Runner from '../assets/img/runner.png'
import 'flexboxgrid'
import '@mapbox/mapbox-gl-geocoder/lib/mapbox-gl-geocoder.css'
import mapboxgl from 'mapbox-gl'
import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder'

const tokenMapBox = import.meta.env.VITE_MAPBOX_API_KEY
const tokenNocodb = import.meta.env.VITE_XC_API_TOKEN

const mapCenter = ref([3, 47])
const isOpen = ref(false)
const position = ref([0, 0])
const content = ref()
const map = ref(null)
const geocoder = ref(null)

const geojsonData = ref({
  type: 'FeatureCollection',
  features: []
})

onMounted(() => {
  getConcess()

  // Initialize MapboxGeocoder
  geocoder.value = new MapboxGeocoder({
    accessToken: tokenMapBox,
    mapboxgl: mapboxgl
  })

  // Append the geocoder to the map container
  map.value.addControl(geocoder.value)
})


const getConcess = async () => {
  const response = await axios.get('', {
    headers: {
    }
  })

  let data = response.data.list


  data.forEach((item) => {
    geojsonData.value.features.push({
      type: 'Feature',
      properties: {
        id: item.Id,
        title: item.titre,
        date: item.date_start,
        ville: item.ville,
        lat: item.latitude,
        lon: item.longitude
      },
      geometry: { type: 'Point', coordinates: [item.longitude, item.latitude] }
    })
  })
}


const flyto = (features) => {
  const { lat, lon, title, date, ville } = features
  map.value.flyTo({ center: [lon, lat], zoom: 14 })
  isOpen.value = false
  openPopup({
    geometry: { coordinates: [lon, lat] },
    properties: { title: title, date: date, ville: ville }
  })
}


const openPopup = async ({ geometry, properties }) => {
  await nextTick()
  console.log(geometry, properties)
  position.value = [...geometry.coordinates]
  isOpen.value = true

  content.value = Object.fromEntries(
    Object.entries(properties).map(([key, value]) => {
      try {
        return [key, JSON.parse(value)]
      } catch (err) {
        // Silence is golden.
      }
      return [key, value]
    })
  )
}
</script>

<template>
  <div class="row">
    <div class="col-xs-3 list">
      <ul>
        <li
          v-for="feature in geojsonData.features"
          :key="feature.properties.id"
          @click="flyto(feature.properties)"
        >
          <h2>{{ feature.properties.title }}</h2>
          <p>{{ feature.properties.date }}</p>
          <p>{{ feature.properties.ville }}</p>
        </li>
      </ul>
    </div>
    <div class="col-xs-9">
      <MapboxMap
        style="height: 400px"
        :access-token="tokenMapBox"
        map-style="mapbox://styles/mapbox/streets-v11"
        :center="mapCenter"
        :zoom="4"
        @mb-created="(mapInstance) => (map = mapInstance)"
      >
        <MapboxPopup
          v-if="isOpen"
          :key="position.join('-')"
          :lng-lat="position"
          anchor="bottom"
          @mb-close="() => (isOpen = false)"
        >
          <h2>{{ content.title }}</h2>
          <p>{{ content.date }}</p>
          <p>{{ content.ville }}</p>
        </MapboxPopup>
        <MapboxImage id="runner" :src="Runner">
          <MapboxCluster
            :data="geojsonData"
            unclustered-point-layer-type="symbol"
            :unclustered-point-layout="{
              'icon-image': 'runner',
              'icon-size': 0.2
            }"
            :unclustered-point-paint="null"
            @mb-feature-click="openPopup"
            :clustersPaint="{
              'circle-color': '#002c5f',
              'circle-radius': 30
            }"
          />
        </MapboxImage>
        <MapboxGeocoder />
      </MapboxMap>
    </div>
  </div>
</template>```

if anyone can help me that would be great !

Add the ability to programmatically trigger a Geolocation with MapboxGeolocateControl

Hi,
it would be useful to implement the trigger() method of the GeolocateControl (https://docs.mapbox.com/mapbox-gl-js/api/markers/#geolocatecontrol#trigger) in the MapboxGeolocateControl component.

We could provide a way to access the Control instance outside of the component, just like we can access the Mapbox instance via @mb-ready @mb-created. Alternatively, maybe that a prop could do the job.

Thanks in advance for taking this into consideration !

Incompatible with mapbox-gl (v3)

Hi,

Mapbox GL JS is currently @3.1.2 with @3.2 in beta.
When I try to install Vue Mapbox GL v2.3.4 it is incompatible with that version:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/mapbox-gl
npm ERR!   mapbox-gl@"^3.1.2" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer mapbox-gl@"^2.8.2" from @studiometa/[email protected]
npm ERR! node_modules/@studiometa/vue-mapbox-gl
npm ERR!   @studiometa/vue-mapbox-gl@"^2.3.4" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

I'd really like to update to that major πŸš€
Is this in the works and will it be addressed soon?

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.