diff --git a/app/assets/javascripts/darkswarm/directives/open_street_map.js.coffee b/app/assets/javascripts/darkswarm/directives/open_street_map.js.coffee index 7dbdc73669..32f0d921b0 100644 --- a/app/assets/javascripts/darkswarm/directives/open_street_map.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/open_street_map.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.directive 'ofnOpenStreetMap', ($window, Enterprises, EnterpriseModal, availableCountries, openStreetMapConfig) -> +Darkswarm.directive 'ofnOpenStreetMap', ($window, MapCentreCalculator, Enterprises, EnterpriseModal, availableCountries, openStreetMapConfig) -> restrict: 'E' replace: true scope: true @@ -11,34 +11,6 @@ Darkswarm.directive 'ofnOpenStreetMap', ($window, Enterprises, EnterpriseModal, 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 @@ -61,28 +33,31 @@ Darkswarm.directive 'ofnOpenStreetMap', ($window, Enterprises, EnterpriseModal, 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) + map.setView([MapCentreCalculator.initialLatitude(), MapCentreCalculator.initialLongitude()], 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) + for enterprise in Enterprises.geocodedEnterprises() + marker = buildMarker(enterprise, { lat: enterprise.latitude, lng: enterprise.longitude }, enterprise.name).addTo(map) + enterpriseNames.push(enterpriseName(enterprise)) + markers.push(marker) + + disableSearchField = () => + $('#open-street-map--search input').prop("disabled", true) displaySearchField = () -> new Autocomplete('#open-street-map--search', onSubmit: goToEnterprise search: searchEnterprises ) - overwriteInlinePositionRelativeToPositionSearchField = -> - $('#open-street-map--search').css("position", "absolute") - overwriteInlinePositionRelativeToPositionSearchField() + overwriteInlinePositionRelativeToAbsoluteOnSearchField() + if Enterprises.geocodedEnterprises().length == 0 + disableSearchField() + + overwriteInlinePositionRelativeToAbsoluteOnSearchField = -> + $('#open-street-map--search').css("position", "absolute") searchEnterprises = (input) -> if input.length < 1 diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 843749c2e6..d8347c7e41 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -84,3 +84,8 @@ Darkswarm.factory 'Enterprises', (enterprises, ShopsResource, CurrentHub, Taxons resetDistance: -> enterprise.distance = null for enterprise in @enterprises + + geocodedEnterprises: => + @enterprises.filter (enterprise) -> + enterprise.latitude? && enterprise.longitude? + diff --git a/app/assets/javascripts/darkswarm/services/map.js.coffee b/app/assets/javascripts/darkswarm/services/map.js.coffee index 2758f299f8..9aa23a7155 100644 --- a/app/assets/javascripts/darkswarm/services/map.js.coffee +++ b/app/assets/javascripts/darkswarm/services/map.js.coffee @@ -2,9 +2,7 @@ Darkswarm.factory "OfnMap", (Enterprises, EnterpriseListModal, MapConfiguration) new class OfnMap constructor: -> @coordinates = {} - @enterprises = Enterprises.enterprises.filter (enterprise) -> - # Remove enterprises w/o lat or long - enterprise.latitude != null || enterprise.longitude != null + @enterprises = Enterprises.geocodedEnterprises() @enterprises = @enterprise_markers(@enterprises) enterprise_markers: (enterprises) -> diff --git a/app/assets/javascripts/darkswarm/services/map_centre_calculator.js.coffee b/app/assets/javascripts/darkswarm/services/map_centre_calculator.js.coffee new file mode 100644 index 0000000000..978afb5858 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/map_centre_calculator.js.coffee @@ -0,0 +1,30 @@ +Darkswarm.factory 'MapCentreCalculator', (Enterprises, openStreetMapConfig) -> + new class MapCentreCalculator + + initialLatitude: => + if Enterprises.geocodedEnterprises().length > 0 + @_calculate("latitude", Enterprises.geocodedEnterprises()) + else + openStreetMapConfig.open_street_map_default_latitude + + initialLongitude: => + if Enterprises.geocodedEnterprises().length > 0 + @_calculate("longitude", Enterprises.geocodedEnterprises()) + else + openStreetMapConfig.open_street_map_default_longitude + + _calculate: (angleName, coordinates) => + angles = [] + + for coordinate in coordinates + angles.push(coordinate[angleName]) + + minimumAngle = Math.min.apply(null, angles) + maximumAngle = Math.max.apply(null, angles) + + distanceBetweenMinimumAndMaximum = if maximumAngle > minimumAngle + maximumAngle - minimumAngle + else + minimumAngle - maximumAngle + + minimumAngle + (distanceBetweenMinimumAndMaximum / 2) diff --git a/app/models/content_configuration.rb b/app/models/content_configuration.rb index 39d4fd9a5c..efe91e05b6 100644 --- a/app/models/content_configuration.rb +++ b/app/models/content_configuration.rb @@ -21,6 +21,8 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration 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: "{}" + preference :open_street_map_default_latitude, :string, default: "-37.4713077" + preference :open_street_map_default_longitude, :string, default: "144.7851531" # Producer sign-up page # All the following defaults using I18n don't work. diff --git a/app/models/preference_sections/map_section.rb b/app/models/preference_sections/map_section.rb index cc16939c36..deed329b44 100644 --- a/app/models/preference_sections/map_section.rb +++ b/app/models/preference_sections/map_section.rb @@ -10,7 +10,9 @@ module PreferenceSections [ :open_street_map_enabled, :open_street_map_provider_name, - :open_street_map_provider_options + :open_street_map_provider_options, + :open_street_map_default_latitude, + :open_street_map_default_longitude ] end end diff --git a/app/serializers/api/open_street_map_config_serializer.rb b/app/serializers/api/open_street_map_config_serializer.rb index 8c5aec5dbb..b24cdcbd41 100644 --- a/app/serializers/api/open_street_map_config_serializer.rb +++ b/app/serializers/api/open_street_map_config_serializer.rb @@ -4,7 +4,9 @@ module Api class OpenStreetMapConfigSerializer < ActiveModel::Serializer attributes :open_street_map_enabled, :open_street_map_provider_name, - :open_street_map_provider_options + :open_street_map_provider_options, + :open_street_map_default_latitude, + :open_street_map_default_longitude def open_street_map_enabled ContentConfig.open_street_map_enabled @@ -17,5 +19,13 @@ module Api def open_street_map_provider_options ContentConfig.open_street_map_provider_options.to_json end + + def open_street_map_default_latitude + ContentConfig.open_street_map_default_latitude + end + + def open_street_map_default_longitude + ContentConfig.open_street_map_default_longitude + end end end diff --git a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee index c95fbdf81b..088ea359e0 100644 --- a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee @@ -24,7 +24,7 @@ describe "Enterprises service", -> {id: 5, visible: true, name: 'e', category: "producer_hub", hubs: [{id: 1}]}, {id: 6, visible: true, name: 'f', category: "producer_shop", hubs: [{id: 2}]}, {id: 7, visible: true, name: 'g', category: "producer", hubs: [{id: 2}]} - {id: 8, visible: true, name: 'h', category: "producer", hubs: [{id: 2}]} + {id: 8, visible: true, name: 'h', category: "producer", hubs: [{id: 2}], latitude: 76.26, longitude: -42.66 } ] H1: 0 beforeEach -> @@ -142,4 +142,8 @@ describe "Enterprises service", -> it "resets the distance", -> Enterprises.resetDistance() for e in Enterprises.enterprises - expect(e.distance).toBeNull() \ No newline at end of file + expect(e.distance).toBeNull() + + describe "geocodedEnterprises", -> + it "only returns enterprises which have a latitude and longitude", -> + expect(Enterprises.geocodedEnterprises()).toEqual [Enterprises.enterprises[7]] diff --git a/spec/javascripts/unit/darkswarm/services/map_centre_calculator_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/map_centre_calculator_spec.js.coffee new file mode 100644 index 0000000000..0d18541442 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/services/map_centre_calculator_spec.js.coffee @@ -0,0 +1,86 @@ +describe 'MapCentreCalculator service', -> + MapCentreCalculator = null + Enterprises = null + defaultLongitude = null + defaultLatitude = null + + beforeEach -> + module 'Darkswarm' + defaultLongitude = -6 + defaultLatitude = 53 + angular.module('Darkswarm').value 'openStreetMapConfig', { + open_street_map_default_latitude: 76.26, + open_street_map_default_longitude: -42.66 + } + + inject (_MapCentreCalculator_, _Enterprises_)-> + MapCentreCalculator = _MapCentreCalculator_ + Enterprises = _Enterprises_ + + describe "initialLatitude", -> + it "calculates the center latitude of any present geocoded enterprises", -> + Enterprises.geocodedEnterprises = -> [ + { latitude: 53, longitude: defaultLongitude }, + { latitude: 54, longitude: defaultLongitude } + ] + + expect(MapCentreCalculator.initialLatitude()).toEqual 53.5 + + it "returns the default configured latitude when there are no geocoded enterprises present", -> + Enterprises.geocodedEnterprises = -> [] + + expect(MapCentreCalculator.initialLatitude()).toEqual 76.26 + + describe "initialLongitude", -> + it "calculates the center longitude of any present geocoded enterprises", -> + Enterprises.geocodedEnterprises = -> [ + { latitude: defaultLatitude, longitude: -6 }, + { latitude: defaultLatitude, longitude: -7 } + ] + + expect(MapCentreCalculator.initialLongitude()).toEqual -6.5 + + it "returns the default configured longitude when there are no geocoded enterprises present", -> + Enterprises.geocodedEnterprises = -> [] + + expect(MapCentreCalculator.initialLongitude()).toEqual -42.66 + + describe "_calculate", -> + it "calculates the average angle correctly when given a single angle", -> + coordinates = [ + { latitude: defaultLatitude, longitude: -7 } + ] + + expect(MapCentreCalculator._calculate("longitude", coordinates)).toEqual -7 + + it "calculates the centre correctly when given a set of positive angles", -> + coordinates = [ + { latitude: 53, longitude: defaultLongitude }, + { latitude: 54, longitude: defaultLongitude } + ] + + expect(MapCentreCalculator._calculate("latitude", coordinates)).toEqual 53.5 + + it "calculates the centre correctly when given a set of negative angles", -> + coordinates = [ + { latitude: defaultLatitude, longitude: -6 }, + { latitude: defaultLatitude, longitude: -7 } + ] + + expect(MapCentreCalculator._calculate("longitude", coordinates)).toEqual -6.5 + + it "calculates the centre correctly when given a mixture of positive and negative angles and the centre is positive", -> + coordinates = [ + { latitude: defaultLatitude, longitude: 7 }, + { latitude: defaultLatitude, longitude: -4 } + ] + + expect(MapCentreCalculator._calculate("longitude", coordinates)).toEqual 1.5 + + it "calculates the centre correctly when given a mixture of positive and negative angles and the centre is negative", -> + coordinates = [ + { latitude: defaultLatitude, longitude: 4 }, + { latitude: defaultLatitude, longitude: -7 } + ] + + expect(MapCentreCalculator._calculate("longitude", coordinates)).toEqual -1.5