mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-27 06:05:19 +00:00
Add support for using Open Street Map on the Map and Group pages.
The map is displayed using https://leafletjs.com/ To enable Open Street Map go to the Admin -> Configuration -> Content section and click 'Open Street Map Enabled'. The 'Open Street Map Provider Name' setting can be used to configure different tile providers thanks to the Leaflet-providers extension (https://github.com/leaflet-extras/leaflet-providers) Some tile providers require an API key, this can provided in JSON format e.g. '{ apiKey: 123 }' in the 'Open Street Map Provider Options' setting. Each tile provider has their own usage policy so this should be checked before enabling Open Street Map. The search field for the Open Street Map works differently than searching on Google Maps. It matches producers by their name or address because it was easier to implement instead of matching place names all over the world.
This commit is contained in:
committed by
Matt-Yorkley
parent
c01da01c70
commit
deafe32354
@@ -8,6 +8,9 @@
|
||||
#= require angular-sanitize
|
||||
#= require angular-animate
|
||||
#= require angular-resource
|
||||
#= require autocomplete.min.js
|
||||
#= require leaflet-1.6.0.js
|
||||
#= require leaflet-providers.js
|
||||
#= require lodash.underscore.js
|
||||
# bluebird.js is a dependency of angular-google-maps.js 2.0.0
|
||||
#= require bluebird.js
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
Darkswarm.directive 'ofnOpenStreetMap', ($window, Enterprises, EnterpriseModal, availableCountries, openStreetMapConfig) ->
|
||||
restrict: 'E'
|
||||
replace: true
|
||||
scope: true
|
||||
template: "<div></div>"
|
||||
|
||||
link: (scope, element, attrs, ctrl, transclude)->
|
||||
map = null
|
||||
markers = []
|
||||
enterpriseNames = []
|
||||
openStreetMapProviderName = openStreetMapConfig.open_street_map_provider_name
|
||||
openStreetMapProviderOptions = JSON.parse(openStreetMapConfig.open_street_map_provider_options)
|
||||
|
||||
average = (values) ->
|
||||
total = values.reduce (sum, value) ->
|
||||
sum = sum + value
|
||||
, 0
|
||||
total / values.length
|
||||
|
||||
averageAngle = (angleName) ->
|
||||
positiveAngles = []
|
||||
negativeAngles = []
|
||||
for enterprise in Enterprises.enterprises
|
||||
if enterprise.latitude? && enterprise.longitude?
|
||||
if enterprise[angleName] > 0
|
||||
positiveAngles.push(enterprise[angleName])
|
||||
else
|
||||
negativeAngles.push(enterprise[angleName])
|
||||
|
||||
averageNegativeAngle = average(negativeAngles)
|
||||
averagePositiveAngle = average(positiveAngles)
|
||||
|
||||
if negativeAngles.length == 0
|
||||
averagePositiveAngle
|
||||
else if positiveAngles.length == 0
|
||||
averageNegativeAngle
|
||||
else if averagePositiveAngle > averageNegativeAngle
|
||||
averagePositiveAngle - averageNegativeAngle
|
||||
else
|
||||
averageNegativeAngle - averagePositiveAngle
|
||||
|
||||
buildMarker = (enterprise, latlng, title) ->
|
||||
icon = L.icon
|
||||
iconUrl: enterprise.icon
|
||||
marker = L.marker latlng,
|
||||
draggable: true,
|
||||
icon: icon,
|
||||
riseOnHover: true,
|
||||
title: title
|
||||
marker.on "click", ->
|
||||
EnterpriseModal.open enterprise
|
||||
marker
|
||||
|
||||
enterpriseName = (enterprise) ->
|
||||
return enterprise.name + " (" + enterprise.address.address1 + ", " + enterprise.address.city + ", " + enterprise.address.state_name + ")";
|
||||
|
||||
goToEnterprise = (selectedEnterpriseName) ->
|
||||
enterprise = Enterprises.enterprises.find (enterprise) ->
|
||||
enterpriseName(enterprise) == selectedEnterpriseName
|
||||
map.setView([enterprise.latitude, enterprise.longitude], 12)
|
||||
|
||||
displayMap = ->
|
||||
setMapDimensions()
|
||||
averageLatitude = averageAngle("latitude")
|
||||
averageLongitude = averageAngle("longitude")
|
||||
zoomLevel = 6
|
||||
map = L.map('open-street-map')
|
||||
L.tileLayer.provider(openStreetMapProviderName, openStreetMapProviderOptions).addTo(map)
|
||||
map.setView([averageLatitude, averageLongitude], zoomLevel)
|
||||
|
||||
displayEnterprises = ->
|
||||
for enterprise in Enterprises.enterprises
|
||||
if enterprise.latitude? && enterprise.longitude?
|
||||
marker = buildMarker(enterprise, { lat: enterprise.latitude, lng: enterprise.longitude }, enterprise.name).addTo(map)
|
||||
enterpriseNames.push(enterpriseName(enterprise))
|
||||
markers.push(marker)
|
||||
|
||||
displaySearchField = () ->
|
||||
new Autocomplete('#open-street-map--search',
|
||||
onSubmit: goToEnterprise
|
||||
search: searchEnterprises
|
||||
)
|
||||
overwriteInlinePositionRelativeToPositionSearchField = ->
|
||||
$('#open-street-map--search').css("position", "absolute")
|
||||
overwriteInlinePositionRelativeToPositionSearchField()
|
||||
|
||||
searchEnterprises = (input) ->
|
||||
if input.length < 1
|
||||
return []
|
||||
enterpriseNames.filter (country) ->
|
||||
country.toLowerCase().includes input.toLowerCase()
|
||||
|
||||
setMapDimensions = ->
|
||||
height = $window.innerHeight - element.offset().top
|
||||
element.css "width", "100%"
|
||||
element.css "height", (height + "px")
|
||||
|
||||
displayMap()
|
||||
displayEnterprises()
|
||||
displaySearchField()
|
||||
@@ -3,6 +3,9 @@
|
||||
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
||||
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
||||
|
||||
*= require autocomplete
|
||||
*= require leaflet
|
||||
|
||||
*= require_self
|
||||
*/
|
||||
@import 'variables';
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
.map-container {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
map, .angular-google-map-container, google-map, .angular-google-map {
|
||||
display: block;
|
||||
@@ -38,6 +39,27 @@
|
||||
background: rgba(255, 255, 255, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#open-street-map {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#open-street-map--search {
|
||||
top: 16px;
|
||||
left: 54px;
|
||||
width: 50%;
|
||||
z-index: 1000;
|
||||
.autocomplete-input,
|
||||
.autocomplete-result-list {
|
||||
border: 2px solid #888;
|
||||
&:hover, &:active, &:focus {
|
||||
border-color: $clr-brick;
|
||||
}
|
||||
}
|
||||
.autocomplete-result-list {
|
||||
border-top: 1px dotted #888;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.map-footer {
|
||||
|
||||
@@ -32,7 +32,8 @@ module Admin
|
||||
PreferenceSections::GroupSignupPageSection.new,
|
||||
PreferenceSections::MainLinksSection.new,
|
||||
PreferenceSections::FooterAndExternalLinksSection.new,
|
||||
PreferenceSections::UserGuideSection.new
|
||||
PreferenceSections::UserGuideSection.new,
|
||||
PreferenceSections::MapSection.new
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -100,6 +100,10 @@ module InjectionHelper
|
||||
inject_json_ams "currencyConfig", {}, Api::CurrencyConfigSerializer
|
||||
end
|
||||
|
||||
def inject_open_street_map_config
|
||||
inject_json_ams "openStreetMapConfig", {}, Api::OpenStreetMapConfigSerializer
|
||||
end
|
||||
|
||||
def inject_spree_api_key
|
||||
render partial: "json/injection_ams", locals: { name: 'spreeApiKey', json: "'#{@spree_api_key}'" }
|
||||
end
|
||||
|
||||
@@ -17,6 +17,11 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration
|
||||
preference :home_show_stats, :boolean, default: true
|
||||
has_attached_file :home_hero, default_url: "/assets/home/home.jpg"
|
||||
|
||||
# Map
|
||||
preference :open_street_map_enabled, :boolean, default: false
|
||||
preference :open_street_map_provider_name, :string, default: "OpenStreetMap.Mapnik"
|
||||
preference :open_street_map_provider_options, :text, default: "{}"
|
||||
|
||||
# Producer sign-up page
|
||||
# All the following defaults using I18n don't work.
|
||||
# https://github.com/openfoodfoundation/openfoodnetwork/issues/3816
|
||||
|
||||
15
app/models/preference_sections/map_section.rb
Normal file
15
app/models/preference_sections/map_section.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
module PreferenceSections
|
||||
class MapSection
|
||||
def name
|
||||
I18n.t('admin.contents.edit.map')
|
||||
end
|
||||
|
||||
def preferences
|
||||
[
|
||||
:open_street_map_enabled,
|
||||
:open_street_map_provider_name,
|
||||
:open_street_map_provider_options
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
15
app/serializers/api/open_street_map_config_serializer.rb
Normal file
15
app/serializers/api/open_street_map_config_serializer.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
class Api::OpenStreetMapConfigSerializer < ActiveModel::Serializer
|
||||
attributes :open_street_map_enabled, :open_street_map_provider_name, :open_street_map_provider_options
|
||||
|
||||
def open_street_map_enabled
|
||||
ContentConfig.open_street_map_enabled
|
||||
end
|
||||
|
||||
def open_street_map_provider_name
|
||||
ContentConfig.open_street_map_provider_name
|
||||
end
|
||||
|
||||
def open_street_map_provider_options
|
||||
ContentConfig.open_street_map_provider_options.to_json
|
||||
end
|
||||
end
|
||||
@@ -6,7 +6,9 @@
|
||||
= @group.logo.url
|
||||
|
||||
- content_for :injection_data do
|
||||
= inject_available_countries
|
||||
= inject_group_enterprises
|
||||
= inject_open_street_map_config
|
||||
|
||||
#group-page.row.pad-top.footer-pad{"ng-controller" => "GroupPageCtrl"}
|
||||
.small-12.columns.pad-top
|
||||
@@ -117,4 +119,4 @@
|
||||
%span
|
||||
= t 'title'
|
||||
|
||||
= render "shared/footer"
|
||||
= render "shared/footer"
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
|
||||
= render "layouts/bugsnag_js"
|
||||
%script{:src => "https://js.stripe.com/v3/", :type => "text/javascript"}
|
||||
%script{src: "//maps.googleapis.com/maps/api/js?libraries=places,geometry#{ ENV['GOOGLE_MAPS_API_KEY'] ? '&key=' + ENV['GOOGLE_MAPS_API_KEY'] : ''} "}
|
||||
- if !ContentConfig.open_street_map_enabled
|
||||
%script{src: "//maps.googleapis.com/maps/api/js?libraries=places,geometry#{ ENV['GOOGLE_MAPS_API_KEY'] ? '&key=' + ENV['GOOGLE_MAPS_API_KEY'] : ''} "}
|
||||
= javascript_include_tag "darkswarm/all"
|
||||
= javascript_include_tag "web/all"
|
||||
= render "layouts/i18n_script"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
= t :label_map
|
||||
|
||||
- content_for :injection_data do
|
||||
= inject_available_countries
|
||||
= inject_enterprise_shopfront_list
|
||||
= inject_open_street_map_config
|
||||
|
||||
= render partial: "shared/map"
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
.map-container
|
||||
%map{"ng-controller" => "MapCtrl"}
|
||||
%ui-gmap-google-map{options: "map.additional_options", center: "map.center", zoom: "map.zoom",
|
||||
styles: "map.styles", draggable: "true"}
|
||||
%map-osm-tiles
|
||||
%map-search
|
||||
%ui-gmap-markers{models: "OfnMap.enterprises", fit: "true",
|
||||
coords: "'self'", icon: "'icon'", click: "'reveal'"}
|
||||
- if ContentConfig.open_street_map_enabled
|
||||
%ofn-open-street-map#open-street-map
|
||||
%div#open-street-map--search
|
||||
%input.autocomplete-input
|
||||
%ul.autocomplete-result-list
|
||||
- else
|
||||
%map{"ng-controller" => "MapCtrl"}
|
||||
%ui-gmap-google-map{options: "map.additional_options", center: "map.center", zoom: "map.zoom",
|
||||
styles: "map.styles", draggable: "true"}
|
||||
%map-osm-tiles
|
||||
%map-search
|
||||
%ui-gmap-markers{models: "OfnMap.enterprises", fit: "true",
|
||||
coords: "'self'", icon: "'icon'", click: "'reveal'"}
|
||||
|
||||
.map-footer
|
||||
%a{:href => "http://www.openstreetmap.org/copyright"} © OpenStreetMap contributors
|
||||
|
||||
@@ -452,6 +452,7 @@ en:
|
||||
footer_and_external_links: Footer and External Links
|
||||
your_content: Your content
|
||||
user_guide: User Guide
|
||||
map: Map
|
||||
|
||||
enterprise_fees:
|
||||
index:
|
||||
|
||||
1
vendor/assets/javascripts/autocomplete.min.js
vendored
Normal file
1
vendor/assets/javascripts/autocomplete.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5
vendor/assets/javascripts/leaflet-1.6.0.js
vendored
Normal file
5
vendor/assets/javascripts/leaflet-1.6.0.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1006
vendor/assets/javascripts/leaflet-providers.js
vendored
Normal file
1006
vendor/assets/javascripts/leaflet-providers.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
vendor/assets/stylesheets/autocomplete.css
vendored
Normal file
1
vendor/assets/stylesheets/autocomplete.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.autocomplete-input{border:1px solid #eee;border-radius:8px;width:100%;padding:12px 12px 12px 48px;box-sizing:border-box;position:relative;font-size:16px;line-height:1.5;flex:1;background-color:#eee;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjY2IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PGNpcmNsZSBjeD0iMTEiIGN5PSIxMSIgcj0iOCIvPjxwYXRoIGQ9Ik0yMSAyMWwtNC00Ii8+PC9zdmc+");background-repeat:no-repeat;background-position:12px}.autocomplete-input:focus,.autocomplete-input[aria-expanded=true]{border-color:rgba(0,0,0,.12);background-color:#fff;outline:none;box-shadow:0 2px 2px rgba(0,0,0,.16)}[data-position=below] .autocomplete-input[aria-expanded=true]{border-bottom-color:transparent;border-radius:8px 8px 0 0}[data-position=above] .autocomplete-input[aria-expanded=true]{border-top-color:transparent;border-radius:0 0 8px 8px;z-index:2}.autocomplete[data-loading=true]:after{content:"";border:3px solid rgba(0,0,0,.12);border-right-color:rgba(0,0,0,.48);border-radius:100%;width:20px;height:20px;position:absolute;right:12px;top:50%;transform:translateY(-50%);animation:rotate 1s linear infinite}.autocomplete-result-list{margin:0;border:1px solid rgba(0,0,0,.12);padding:0;box-sizing:border-box;max-height:296px;overflow-y:auto;background:#fff;list-style:none;box-shadow:0 2px 2px rgba(0,0,0,.16)}[data-position=below] .autocomplete-result-list{margin-top:-1px;border-top-color:transparent;border-radius:0 0 8px 8px;padding-bottom:8px}[data-position=above] .autocomplete-result-list{margin-bottom:-1px;border-bottom-color:transparent;border-radius:8px 8px 0 0;padding-top:8px}.autocomplete-result{cursor:default;padding:12px 12px 12px 48px;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjY2NjIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PGNpcmNsZSBjeD0iMTEiIGN5PSIxMSIgcj0iOCIvPjxwYXRoIGQ9Ik0yMSAyMWwtNC00Ii8+PC9zdmc+");background-repeat:no-repeat;background-position:12px}.autocomplete-result:hover,.autocomplete-result[aria-selected=true]{background-color:rgba(0,0,0,.06)}@keyframes rotate{0%{transform:translateY(-50%) rotate(0deg)}to{transform:translateY(-50%) rotate(359deg)}}
|
||||
640
vendor/assets/stylesheets/leaflet.css
vendored
Normal file
640
vendor/assets/stylesheets/leaflet.css
vendored
Normal file
@@ -0,0 +1,640 @@
|
||||
/* required styles */
|
||||
|
||||
.leaflet-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-pane > svg,
|
||||
.leaflet-pane > canvas,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
/* Prevents IE11 from highlighting tiles in blue */
|
||||
.leaflet-tile::selection {
|
||||
background: transparent;
|
||||
}
|
||||
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
|
||||
.leaflet-safari .leaflet-tile {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
}
|
||||
/* hack that prevents hw layers "stretching" when loading new tiles */
|
||||
.leaflet-safari .leaflet-tile-container {
|
||||
width: 1600px;
|
||||
height: 1600px;
|
||||
-webkit-transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
|
||||
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container .leaflet-overlay-pane svg,
|
||||
.leaflet-container .leaflet-marker-pane img,
|
||||
.leaflet-container .leaflet-shadow-pane img,
|
||||
.leaflet-container .leaflet-tile-pane img,
|
||||
.leaflet-container img.leaflet-image-layer,
|
||||
.leaflet-container .leaflet-tile {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
}
|
||||
|
||||
.leaflet-container.leaflet-touch-zoom {
|
||||
-ms-touch-action: pan-x pan-y;
|
||||
touch-action: pan-x pan-y;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag {
|
||||
-ms-touch-action: pinch-zoom;
|
||||
/* Fallback for FF which doesn't support pinch-zoom */
|
||||
touch-action: none;
|
||||
touch-action: pinch-zoom;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.leaflet-container {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.leaflet-container a {
|
||||
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
|
||||
}
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width: 0;
|
||||
height: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
z-index: 800;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-pane { z-index: 400; }
|
||||
|
||||
.leaflet-tile-pane { z-index: 200; }
|
||||
.leaflet-overlay-pane { z-index: 400; }
|
||||
.leaflet-shadow-pane { z-index: 500; }
|
||||
.leaflet-marker-pane { z-index: 600; }
|
||||
.leaflet-tooltip-pane { z-index: 650; }
|
||||
.leaflet-popup-pane { z-index: 700; }
|
||||
|
||||
.leaflet-map-pane canvas { z-index: 100; }
|
||||
.leaflet-map-pane svg { z-index: 200; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.leaflet-control {
|
||||
position: relative;
|
||||
z-index: 800;
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-top {
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-right {
|
||||
right: 0;
|
||||
}
|
||||
.leaflet-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.leaflet-left {
|
||||
left: 0;
|
||||
}
|
||||
.leaflet-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
float: right;
|
||||
}
|
||||
.leaflet-top .leaflet-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.leaflet-left .leaflet-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-tile {
|
||||
will-change: opacity;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
.leaflet-zoom-animated {
|
||||
-webkit-transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
will-change: transform;
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* cursors */
|
||||
|
||||
.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-grab {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
.leaflet-crosshair,
|
||||
.leaflet-crosshair .leaflet-interactive {
|
||||
cursor: crosshair;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor: auto;
|
||||
}
|
||||
.leaflet-dragging .leaflet-grab,
|
||||
.leaflet-dragging .leaflet-grab .leaflet-interactive,
|
||||
.leaflet-dragging .leaflet-marker-draggable {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* marker & overlays interactivity */
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-pane > svg path,
|
||||
.leaflet-tile-container {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.leaflet-interactive,
|
||||
.leaflet-image-layer.leaflet-interactive,
|
||||
.leaflet-pane > svg path.leaflet-interactive,
|
||||
svg.leaflet-image-layer.leaflet-interactive path {
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* visual tweaks */
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline: 0;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-container a.leaflet-active {
|
||||
outline: 2px solid orange;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.leaflet-bar a.leaflet-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-bar a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:first-child {
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers-2x.png);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.leaflet-control-layers-scrollbar {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
/* Default icon URLs */
|
||||
.leaflet-default-icon-path {
|
||||
background-image: url(images/marker-icon.png);
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-container .leaflet-control-attribution,
|
||||
.leaflet-container .leaflet-control-scale {
|
||||
font-size: 11px;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution,
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 19px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 18px 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -20px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.leaflet-popup-content-wrapper,
|
||||
.leaflet-popup-tip {
|
||||
background: white;
|
||||
color: #333;
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 4px 4px 0 0;
|
||||
border: none;
|
||||
text-align: center;
|
||||
width: 18px;
|
||||
height: 14px;
|
||||
font: 16px/14px Tahoma, Verdana, sans-serif;
|
||||
color: #c3c3c3;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover {
|
||||
color: #999;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip-container {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
|
||||
/* Tooltip */
|
||||
/* Base styles for the element that has a tooltip */
|
||||
.leaflet-tooltip {
|
||||
position: absolute;
|
||||
padding: 6px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 3px;
|
||||
color: #222;
|
||||
white-space: nowrap;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-tooltip.leaflet-clickable {
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-tooltip-top:before,
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border: 6px solid transparent;
|
||||
background: transparent;
|
||||
content: "";
|
||||
}
|
||||
|
||||
/* Directions */
|
||||
|
||||
.leaflet-tooltip-bottom {
|
||||
margin-top: 6px;
|
||||
}
|
||||
.leaflet-tooltip-top {
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-top:before {
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-top:before {
|
||||
bottom: 0;
|
||||
margin-bottom: -12px;
|
||||
border-top-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before {
|
||||
top: 0;
|
||||
margin-top: -12px;
|
||||
margin-left: -6px;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-left {
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-right {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
top: 50%;
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before {
|
||||
right: 0;
|
||||
margin-right: -12px;
|
||||
border-left-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-right:before {
|
||||
left: 0;
|
||||
margin-left: -12px;
|
||||
border-right-color: #fff;
|
||||
}
|
||||
Reference in New Issue
Block a user