Skip to content

Instantly share code, notes, and snippets.

@leastbad
Last active April 15, 2021 22:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leastbad/d74ccc570382b8f741255452327ae259 to your computer and use it in GitHub Desktop.
Save leastbad/d74ccc570382b8f741255452327ae259 to your computer and use it in GitHub Desktop.
Mapbox controller

Using Stimulus v2, FontAwesome 5, Bootstrap 5, and Mapbox

You can grab a copy of marker.svg here - put it in your /public folder.

<div
id="mapbox"
class="p-4"
data-controller="mapbox"
data-mapbox-base-lat-lng-value="[37.57,-122.26]"
data-mapbox-zoom-value="10"
data-mapbox-max-zoom-value="18"
data-mapbox-id-value="mapbox/light-v10"
data-mapbox-token-value="<%= ENV.fetch("MAPBOX_TOKEN") {} %>"
data-mapbox-listings-value='[{"url":"/","latLng":[37.7,-122.41],"name":"Call with Jane","date":"Tomorrow at 12:30 PM"},{"url":"/","latLng":[37.59,-122.39],"name":"HackTM conference","date":"In about 5 minutes"},{"url":"/","latLng":[37.52,-122.29],"name":"Marketing event","date":"Today at 1:00 PM"},{"url":"/","latLng":[37.37,-122.12],"name":"Dinner with partners","date":"In 2 hours"},{"url":"/","latLng":[37.36,-121.94],"name":"Interview with Google","date":"In two days at 15:00 PM"}]'
></div>
<button data-reflex="Map#update" data-lat="37.7" data-lng="-122.41">Update</button>
class MapReflex < ApplicationReflex
def update
lat = element.dataset["data-lat"]
lng = element.dataset["data-lng"]
# do your SQL call or whatever
cable_ready.dispatch_event(selector: "#mapbox", name: "mapbox:update", detail: {listings: ARRAY_OF_RESULTS.to_json}).broadcast
morph :nothing
end
end
import { Controller } from 'stimulus'
import L from 'leaflet'
import 'leaflet/dist/leaflet.css'
export default class extends Controller {
static values = {
listings: Array,
baseLatLng: Array,
zoom: Number,
token: String,
id: String,
maxZoom: Number
}
connect () {
this.element.addEventListener('mapbox:update', this.update)
const icon = L.icon({
iconUrl: '/marker.svg',
iconSize: [38, 95], // size of the icon
shadowSize: [50, 64], // size of the shadow
iconAnchor: [22, 94], // point of the icon which will correspond to marker's location
shadowAnchor: [4, 62], // the same for the shadow
popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor
})
const mapListings = L.map(this.element).setView(
this.baseLatLngValue,
this.zoomValue
)
L.tileLayer(
'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}',
{
attribution:
'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: this.maxZoomValue,
id: this.idValue,
accessToken: this.tokenValue
}
).addTo(mapListings)
this.listingsValue.forEach(listing => {
const popupHtml = `
<a href="${listing.url}" class="card card-article-wide border-0 flex-column no-gutters no-hover">
<div class="card-body py-0 d-flex flex-column justify-content-between col-12">
<h4 class="h5 fw-normal mb-2">${listing.name}</h4>
<div class="d-flex">
<div class="icon icon-xs icon-tertiary me-2"><span class="fas fa-clock"></span></div>
<div class="font-xs text-dark mw-content">${listing.date}</div>
</div>
</div>
</a>
`
const marker = L.marker(listing.latLng, { icon: icon }).addTo(mapListings)
marker.bindPopup(popupHtml)
})
}
disconnect () {
this.element.removeEventListener('mapbox:update', this.update)
}
update = e => {
console.log(e.detail)
// you can send arbitrary data to the detail object using dispatch_event
// eg. const listings = e.detail.listings
// what you'll need to do is take listings and pass it to your this.mapListings using the leaflet API
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment