visgl / react-map-gl

React friendly API wrapper around MapboxGL JS
http://visgl.github.io/react-map-gl/
Other
7.87k stars 1.36k forks source link

Is it possible to display routes? #591

Closed sachinshettigar closed 5 years ago

sachinshettigar commented 6 years ago

I want to use Mapbox for one of my projects and was thinking of using this library to use it in react. I want a feature where i can display routes with multiple stops along the routes. I see that mapbox has a directions API to get direction info and layers API to display the route for this purpose. I don't see any such thing in here.

Can we display routes using this library. If yes how? A small example would be really helpful.

GunnarSturla commented 6 years ago

I'm having the same issue on my end, and from what I gather, there are three ways do draw lines/routes using this library.

First, and probably the easiest is using deck.gl's LineLayer. Deck.gl is a companion library of this one, they're both managed by Uber, and deck.gl is great to do all sorts of data visualizations on top of your maps. If all we need is to draw a line, however, it would probably bloat the bundle.

The second way is to add a GeoJSON layer to our mapStyle. You can see how it's done in the GeoJSON example. This is the way I'm currently doing it, but I find that working with the mapStyle and GeoJSON is neither easy nor readable. I would also like to have an easier way to use React's composition model, so I could have my line/route components as children of ReactMapGL, similar to how the marker control works.

The last way I've found is to create a custom overlay. This is probably the way I would like to go, but the documentation around it isn't very extensive. I found a folder with various overlay examples, but none of them make lines (as far as I could tell). The draggable points overlay might be the place to start, but I haven't gotten that far.

My dream scenario would be to have a line component that you could place inside the ReactMapGl component, just like the Marker and like react-leaflet's PolyLine works.

<ReactMapGL latitude={64.14} longitude={-20.22} zoom={8}>
  <PloyLine positions={[
    [-21.81884765625, 64.1297836764257],
    [-19.79736328125, 64.1585310519412]]}
  />
</ReactMapGL>

I'm not really happy with my solution to add the GeoJSON to the mapStyle so I plan on redoing it. My question to the maintainers is; would you accept a pr that adds a PolyLine component, similar to the Marker component, or should I create a custom overlay instead?

secretwpn commented 5 years ago

One approach, as mentioned above already, would be to go with a custom overlay. I've used the ScatterOverlay example to create my own PolylineOverlay

import React, { PureComponent } from 'react'
import { CanvasOverlay } from 'react-map-gl'

export default class PolylineOverlay extends PureComponent {
  _redraw ({ width, height, ctx, isDragging, project, unproject }) {
    const { points, color = 'red', lineWidth = 2, renderWhileDragging = true } = this.props
    ctx.clearRect(0, 0, width, height)
    ctx.globalCompositeOperation = 'lighter'

    if ((renderWhileDragging || !isDragging) && points) {
      ctx.lineWidth = lineWidth
      ctx.strokeStyle = color
      ctx.beginPath()
      points.forEach(point => {
        const pixel = project([point[0], point[1]])
        ctx.lineTo(pixel[0], pixel[1])
      })
      ctx.stroke()
    }
  }

  render () {
    return <CanvasOverlay redraw={this._redraw.bind(this)} />
  }
}

and then use it as follows

// points is an array of [[lat, lon], [lat, lon], ...]
<ReactMapGL ...>
  <PolylineOverlay points={points} />
</ReactMapGL>

This works quite well for my application

YIPG commented 5 years ago

@GunnarSturla Really helpful!! I also tried to create GeoJSON to add the line layer too. My process is like

  1. Get GeoJSON of the route by API here
    {
    "routes": [
    {
      "geometry": {
        "coordinates": [
          [
            -73.98891,
            40.733122
          ],
          [
            -73.994118,
            40.735313
          ],
          [
            -73.996976,
            40.731414
          ],
          [
            -74.000066,
            40.732929
          ],
          [
            -74.00001,
            40.733004
          ]
        ],
        "type": "LineString"
      },
      "legs": [
        {
          "summary": "",
          "weight": 582.4,
          "duration": 380.6,
          "steps": [],
          "distance": 1317.9
        }
      ],
      "weight_name": "routability",
      "weight": 582.4,
      "duration": 380.6,
      "distance": 1317.9
    }
    ],
    "waypoints": [
    {
      "distance": 15.535684098115707,
      "name": "East 13th Street",
      "location": [
        -73.98891,
        40.733122
      ]
    },
    {
      "distance": 0.9545121434133703,
      "name": "6th Avenue",
      "location": [
        -74.00001,
        40.733004
      ]
    }
    ],
    "code": "Ok"
    }
  2. Checked the Animating GeoJSON example. Then I realized that the GeoJSON format in the mapbox-gl or react-map-gl is quite different from the one I got above. Then I changed the above one to the below one.
    
    "sources": {
        "route": {
            "type": "geojson",
            "data": {
                "type": "LineString",
                "coordinates": [
                    [-122.48369693756104, 37.83381888486939],
                    [-122.48348236083984, 37.83317489144141],
                    [-122.48339653015138, 37.83270036637107],
                ]
            }
        }
    },

"layers": [ { "id": "route", "type": "line", "source": "route", "layout": { "line-join": "round", "line-cap": "round" }, "paint": { "line-color": "#f06292", "line-width": 15 } }, ]


But sadly, it didn't work in my application. (I mean the routing path doesn't appear in a map.)

3. I actually don't wanna give a try to Overlay something because it seems very relevant to D3.js and looks complicated.

I'm gonna work on Deck.gl's line layer or change to the Google Map. If there are the people well-informed of GeoJSON, please teach me how to show the line.

ps:
I found how to use mapbox-gl's instance. [link](https://stackoverflow.com/questions/47916941/can-i-add-a-geojson-line-like-they-do-in-the-mapbox-gl-js-documentation-using)
Then, follow [this ref](https://docs.mapbox.com/help/tutorials/getting-started-directions-api/)
related #429 
GunnarSturla commented 5 years ago

@YIPG: I don't think the object you're using is correct. I'm not really an expert in GeoJSON but I've found geojson.io to be very helpful in visualizing my code.

I built the line you're trying to draw there and got this:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "stroke": "#f06292",
        "stroke-width": 15,
        "stroke-opacity": 1,
        "line-join": "round",
        "line-cap": "round"
      },
      "geometry": {
        "type": "LineString",
        "coordinates": [
                    [-122.48369693756104, 37.83381888486939],
                    [-122.48348236083984, 37.83317489144141],
                    [-122.48339653015138, 37.83270036637107]
        ]
      }
    }
  ]
}

Try seeing if that works, but did you try @secretwpn's overlay, it looks very promising?

YIPG commented 5 years ago

@GunnarSturla Thank you for your reply. I stuck with GeoJSON. I tried @secretwpn's polylineoverlay and it's totally working well! (And of course, your way is correctly working)

DiwasSubedi commented 5 years ago

Does any one has a working example which uses map box routes api and plot routes from the response on map ?

jakeols commented 5 years ago

Hey @DiwasSubedi , I'm not sure if this is what you're looking for, but here's an example of how I did it recently as a gist here. I didn't end up going with this library, but the concept is essentially the same.

sharpar commented 4 years ago
// points is an array of [[lat, lon], [lat, lon], ...]
<ReactMapGL ...>
  <PolylineOverlay points={points} />
</ReactMapGL>

Just in case anyone is trying and it isn't working, the format of the array should have the longitude first, then the latitude. So [[lon, lat], [lon, lat], ...].

project in CanvasOverlay expects the longitude first - https://github.com/visgl/react-map-gl/blob/master/docs/api-reference/canvas-overlay.md

@secretwpn thanks for your help!

ariel262626 commented 4 years ago

Any updated solution? Can someone post a full example of draw simple polylines on the react-map-gl?

sharpar commented 4 years ago

@ariel262626 you could try using DeckGL and PathLayer: https://deck.gl/docs/api-reference/layers/path-layer

I tried using the custom overlay and got it working, but it was performing too slow when I had a lot of routes, so I switched to DeckGL. This medium post was helpful: https://medium.com/@sashakayola/map-layering-using-mapbox-gl-js-deck-gl-react-ba0ece89aaef

AlfieFeldspar commented 4 years ago

I think I'm too new at this stuff, but in the deck tutorial, they say "I specified an array of coordinates to form my path from point A to point B. Add in whatever data is appropriate for your particular overlay." The data I received from the Optimization API is not an array of coords - it delivers a mysterious "geometry" string. Anyone have experience with this?

ariel262626 commented 4 years ago

I think I'm too new at this stuff, but in the deck tutorial, they say "I specified an array of coordinates to form my path from point A to point B. Add in whatever data is appropriate for your particular overlay." The data I received from the Optimization API is not an array of coords - it delivers a mysterious "geometry" string. Anyone have experience with this?

Yep, you can use the geometry as the data of the GeoJsonLayer:

 const layer = new GeoJsonLayer({
   id: 'geojson-layer',
   data: getGeometry(),
   pickable: true,
   stroked: false,
   filled: true,
   extruded: true,
   lineWidthScale: 20,
   lineWidthMinPixels: 2,
   getFillColor: [160, 160, 180, 200],
   getLineColor: d => colorToRGBArray(d.properties.color),
   getRadius: 100,
   getLineWidth: 1,
   getElevation: 30
 });

And then pass it to your DeckGL layers prop.

Check the docs here: https://deck.gl/docs/api-reference/layers/geojson-layer

AlfieFeldspar commented 4 years ago

Thank you so much for responding! A human being! :) <3 Since writing, I have figured out how to get an assembled coordinate list for my line (yay!). Can I pass that list to the data here?

I have two branches of my project with equally dysfunctional lines (=no lines with hardcoded data). https://github.com/AlfieFeldspar/optimizedTravel

I don't suppose I could buy someone a venmo coffee/consulting fee for a 30 min zoom to help get this organized? I am at end of all wits.

Essentially: -I have a map displaying points (static locations from my database) -I have a button for 'route generation' that hits the Mapbox Optimization API, assembles the coordinates and adds them to a possibly appropriate geojson object, and then I want them to load. -nothing fancy - no animation or anything.

Gratitude for any further guidance.

On Sun, Nov 1, 2020 at 3:30 AM ariel262626 notifications@github.com wrote:

I think I'm too new at this stuff, but in the deck tutorial, they say "I specified an array of coordinates to form my path from point A to point B. Add in whatever data is appropriate for your particular overlay." The data I received from the Optimization API is not an array of coords - it delivers a mysterious "geometry" string. Anyone have experience with this?

Yep, you can use the geometry as the data of the GeoJsonLayer:

const layer = new GeoJsonLayer({ id: 'geojson-layer', data: getGeometry(), pickable: true, stroked: false, filled: true, extruded: true, lineWidthScale: 20, lineWidthMinPixels: 2, getFillColor: [160, 160, 180, 200], getLineColor: d => colorToRGBArray(d.properties.color), getRadius: 100, getLineWidth: 1, getElevation: 30 }); And then pass it to your DeckGL layers prop.

Check the docs here: https://deck.gl/docs/api-reference/layers/geojson-layer

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/visgl/react-map-gl/issues/591#issuecomment-720053489, or unsubscribe https://github.com/notifications/unsubscribe-auth/AP25TWPDXLFLWRW5FMU6WJLSNUMARANCNFSM4FUSXHYA .

mathjp commented 3 years ago

I am having an issue with routes, currently, it's going out of routes. I am using ScatterOverlay example to show the routes but whenever I zoom in few routes are going out of roads image

nonoumasy commented 3 years ago

I was able to use the suggested canvas overlay to draw lines in between my location data. I used the PolylineOverlay code above and then just customized the ctx stuff. Would have like to have used arcTo or bezierTo, but they were complicated. lineTo was simple.

Screen Shot 2021-03-22 at 3 52 15 AM