Skip to content

Instantly share code, notes, and snippets.

@Jks15063
Created December 2, 2016 00:00
Show Gist options
  • Save Jks15063/38d7160c929e99498ebab3bcdfc036ad to your computer and use it in GitHub Desktop.
Save Jks15063/38d7160c929e99498ebab3bcdfc036ad to your computer and use it in GitHub Desktop.
finiteBounds = (bounds) ->
ne = bounds.northeast
sw = bounds.southwest
return (isFinite(ne.lat) && isFinite(ne.lng) && isFinite(sw.lat) && isFinite(sw.lng))
getBoundsZoomLevel = (bounds, size) ->
latRad = (lat) ->
sin = Math.sin(lat * Math.PI / 180)
radX2 = Math.log((1 + sin) / (1 - sin)) / 2
Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2
zoom = (mapPx, worldPx, fraction) ->
Math.floor Math.log((mapPx / worldPx) / fraction) / Math.LN2
WORLD_DIM =
height: 256
width: 256
ZOOM_MAX = 21
ne = bounds.northeast
sw = bounds.southwest
return 8 if not finiteBounds(bounds)
latFraction = (latRad(ne.lat) - latRad(sw.lat)) / Math.PI
lngDiff = ne.lng - sw.lng
lngFraction = ((if (lngDiff < 0) then (lngDiff + 360) else lngDiff)) / 360
latZoom = zoom(size.y, WORLD_DIM.height, latFraction)
lngZoom = zoom(size.x, WORLD_DIM.width, lngFraction)
Math.min latZoom, lngZoom, ZOOM_MAX
maps = angular.module('wm-maps')
maps.directive 'wmListingsMap', ($rootScope, wmMarkerService, $timeout, wmHelpers) ->
class Controller
constructor: ($scope, $modal, $window, leafletData) ->
$scope.mapControl = leafletData
$scope.limitZoomReload = true
$scope.$on 'leafletDirectiveMap.dragend', (event, args) ->
amountMoved = args?.leafletEvent?.distance
mapHeight = args?.leafletEvent?.target?._size?.y
if !amountMoved || !mapHeight || amountMoved > mapHeight * 0.35
$scope.userMovedMap()
$scope.$on 'leafletDirectiveMap.zoomend', (event, args) ->
if $scope.mapLoaded
newZoom = args?.leafletEvent?.target?._zoom
# Don't reload pins if user is zooming in after initial load.
if !$scope.limitZoomReload || !newZoom || newZoom < $scope.zoom
# After user has zoomed out, reload pins every zoom.
$scope.limitZoomReload = false
$scope.userMovedMap()
else
$scope.userMovedMap()
$scope.$on 'wmListingDetail.clicked', (_event, listing) ->
listing.marker._cachedEventName = _event.name
listing.marker?.openPopup()
if $scope.bounds && finiteBounds($scope.bounds)
bounds = new L.latLngBounds(
new L.latLng($scope.bounds.southwest.lat, $scope.bounds.southwest.lng),
new L.latLng($scope.bounds.northeast.lat, $scope.bounds.northeast.lng),
)
center = bounds.getCenter()
$scope.center =
lat: center.lat
lng: center.lng
zoom: window.defaultMapZoom
else if $rootScope?.regionData?.location?
location = $rootScope.regionData.location
$scope.center =
lat: location.latitude
lng: location.longitude
zoom: window.defaultMapZoom
$scope.widenSearch = ->
$scope.mapControl.getMap().then (map) =>
size = map.getSize()
$scope.zoom = getBoundsZoomLevel($scope.bounds, size) - 1
map.setZoom($scope.zoom - 1)
$scope.updateBounds
if $scope.modal?
$('.modal').css('display', 'none')
if $rootScope.siteScope == 'dispensary'
$scope.listingType = 'storefronts'
$scope.lookForType = 'deliveries'
$scope.lookForOther = ->
$window.location.href = '/deliveries?from-region=' + $rootScope.regionData.name
this.$hide()
else
$scope.listingType = 'deliveries'
$scope.lookForType = 'storefronts'
$scope.lookForOther = ->
$window.location.href = '/dispensaries?from-region=' + $rootScope.regionData.name
show = ->
($rootScope.regionData?.name != undefined) &&
$scope.listings.length == 0 &&
!$rootScope.isCardsMap &&
($rootScope.siteScope == 'dispensary' || $rootScope.siteScope == 'delivery')
$scope.noListings = ->
if $scope.modal?
$('.modal').css('display', 'block')
else
console.log('CREATE')
$scope.modal = $modal(
template:'modal/noListings.html',
show: show(),
scope: $scope
)
# console.log('HEAD')
# $scope.noListings()
onEachFeature = (feature, layer) ->
editLink = '/new_admin/regions/' + feature.properties.slug + '/edit'
popupContent = '<div id="wm_map_infobox_content">' +
'<div class="region_name hovers">' +
"<a target=\"_blank\" href=\"#{editLink}\">" + feature.properties.name + '</a>' +
'</div>' +
'</div>'
layer.bindPopup popupContent
return
geoData = []
addRegionGeoJson = (_region) ->
if _region?.geometry
geojson = JSON.parse(_region.geometry)
geojson.properties =
name: _region.name
slug: _region.slug
geoData.push(geojson)
addRegionGeoJson($rootScope.regionData)
if $scope.subregions
$scope.subregions.forEach (_region) ->
addRegionGeoJson(_region)
angular.extend $scope,
mapOptions:
scrollWheelZoom: true
attributionControl: false
tileLayer: window.tileServerUrl
zoomControlPosition: 'topright'
tileLayerOptions: window.tileLayerDefaults
center: $scope.center
markers: []
controls:
custom: new L.control.attribution(prefix: false)
geojson:
data:
"type": "FeatureCollection"
"features": geoData
style:
fillColor: 'teal'
weight: 1
opacity: 1
color: 'white'
dashArray: '3'
fillOpacity: 0.4
onEachFeature: onEachFeature
link = ($scope, $el, $attrs, listingsController) ->
$scope.updateBounds = listingsController.updateBounds
if $rootScope.wmRollout?.new_header
$el.addClass('with-new-header')
$scope.centerChanged = ->
listingsController.centerChanged()
$scope.userMovedMap = =>
$timeout.cancel @userMovedMapDebounce
@userMovedMapDebounce = $timeout (=>
# We don't want to call centerChanged() until after the map has
# loaded and had all its initial values set. This happens after
# $scope.zoom is set.
if $scope.mapLoaded
$rootScope.lockedToRegion = false
$scope.updateBounds()
$scope.centerChanged()
$scope.mapLoaded = !!$scope.zoom
), 200
resetMarkers = (map) ->
for marker in $scope.markers
map.removeLayer(marker)
$scope.markers = []
addListings = (map, listings) ->
if listings && listings.length > 0
for listing, index in listings
marker = wmMarkerService.setupMarker(listing, map, $scope)
$scope.markers.push(marker)
fitMapToListingCards = (map, listings) ->
if listings && listings.length > 0
# Create L.latLng objs for all listings and fit the map to show them.
ltlngs = []
listings.forEach (listing) =>
ltlngs.push(new L.latLng(listing.latitude, listing.longitude))
map.fitBounds(L.latLngBounds(ltlngs))
# If we are zoomed in too much then set the map zoom to our default.
if map.getZoom() > window.defaultMapZoom # FIXME: Is this what we want for the min?
map.setZoom(window.defaultMapZoom)
# Set the starting zoom to the zoom for cards.
$scope.zoom = map.getZoom()
# We finished showing the cards. From now on we are showing regular listings.
$rootScope.isCardsMap = false
# Make sure the map is considered loaded.
$scope.mapLoaded = true
# Load more pins to fill map.
$scope.userMovedMap()
# NOTE: here
$scope.$watch 'listings', (listings) ->
$scope.mapControl.getMap().then (map) ->
if listings.length is 0
$scope.noListings()
else
if $scope.modal?
$('.modal').css('display', 'none')
resetMarkers(map)
addListings(map, listings)
# If we are showing markers for Cards. Fit to cards and fill map with other markers.
fitMapToListingCards(map, listings) if $rootScope.isCardsMap
$scope.$watch 'bounds', (bounds) ->
$scope.updateBounds()
$scope.mapControl.getMap().then (map) ->
size = map.getSize()
if !bounds || size.x == 0
$scope.zoom = map.getZoom()
$scope.mapLoaded = true
return
$scope.zoom = getBoundsZoomLevel($scope.bounds, size)
current_zoom = map.getZoom()
if $scope.zoom == current_zoom
$scope.mapLoaded = true
else
map.setZoom($scope.zoom)
$scope.$on '$destroy', =>
$timeout.cancel @updateListingsDebounce
params = wmHelpers.userLocationParams
'listing type': $scope.lookForType
'page url': window.location.href
if window.location.pathname.match(/\/nearby|in\//i)
wmHelpers.logAnalyticsEvent 'region - viewed map page', params
restrict: 'E'
templateUrl: 'wm_maps/listings_map.html'
require: '^wmListings'
controller: ['$scope', '$modal', '$window', 'leafletData', Controller]
link: link
scope: true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment