geo_concerns 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rubocop.yml +101 -0
- data/.travis.yml +17 -0
- data/Gemfile +46 -0
- data/LICENSE +202 -0
- data/README.md +46 -0
- data/Rakefile +21 -0
- data/app/actors/geo_concerns/file_actor.rb +20 -0
- data/app/actors/geo_concerns/file_set_actor.rb +7 -0
- data/app/assets/images/geo_concerns/.keep +0 -0
- data/app/assets/images/geo_concerns/images/geocoder.png +0 -0
- data/app/assets/images/geo_concerns/images/throbber.gif +0 -0
- data/app/assets/images/geo_concerns/img/filter-icon.png +0 -0
- data/app/assets/images/geo_concerns/img/move-handle.png +0 -0
- data/app/assets/images/geo_concerns/img/resize-handle.png +0 -0
- data/app/assets/javascripts/geo_concerns/Control.Geocoder.js +1056 -0
- data/app/assets/javascripts/geo_concerns/application.js +5 -0
- data/app/assets/javascripts/geo_concerns/bounding_box_selector.js +100 -0
- data/app/assets/javascripts/geo_concerns/leaflet-boundingbox.js +467 -0
- data/app/assets/stylesheets/geo_concerns/Control.Geocoder.css +104 -0
- data/app/assets/stylesheets/geo_concerns/application.css +18 -0
- data/app/assets/stylesheets/geo_concerns/bounding_box.scss +7 -0
- data/app/assets/stylesheets/geo_concerns/leaflet-boundingbox.css +17 -0
- data/app/controllers/concerns/geo_concerns/file_sets_controller_behavior.rb +19 -0
- data/app/controllers/concerns/geo_concerns/image_works_controller_behavior.rb +13 -0
- data/app/controllers/concerns/geo_concerns/raster_works_controller_behavior.rb +23 -0
- data/app/controllers/concerns/geo_concerns/vector_works_controller_behavior.rb +23 -0
- data/app/forms/geo_concerns/basic_geo_metadata_form.rb +8 -0
- data/app/forms/geo_concerns/external_metadata_file_form.rb +8 -0
- data/app/forms/geo_concerns/georeferenced_form.rb +9 -0
- data/app/forms/geo_concerns/image_work_form.rb +9 -0
- data/app/forms/geo_concerns/raster_work_form.rb +8 -0
- data/app/forms/geo_concerns/vector_work_form.rb +8 -0
- data/app/helpers/bounding_box_helper.rb +24 -0
- data/app/helpers/geo_concerns/application_helper.rb +4 -0
- data/app/models/concerns/geo_concerns/basic_geo_metadata.rb +21 -0
- data/app/models/concerns/geo_concerns/external_metadata_file_behavior.rb +31 -0
- data/app/models/concerns/geo_concerns/extractors/fgdc_helper.rb +9 -0
- data/app/models/concerns/geo_concerns/extractors/fgdc_metadata_extractor.rb +114 -0
- data/app/models/concerns/geo_concerns/extractors/iso19139_helper.rb +50 -0
- data/app/models/concerns/geo_concerns/extractors/mods_helper.rb +15 -0
- data/app/models/concerns/geo_concerns/file_set/derivatives.rb +60 -0
- data/app/models/concerns/geo_concerns/file_set_presenter_behavior.rb +7 -0
- data/app/models/concerns/geo_concerns/geo_file_format_behavior.rb +37 -0
- data/app/models/concerns/geo_concerns/geo_file_set_behavior.rb +11 -0
- data/app/models/concerns/geo_concerns/georeferenced_behavior.rb +18 -0
- data/app/models/concerns/geo_concerns/image_file_behavior.rb +14 -0
- data/app/models/concerns/geo_concerns/image_work_behavior.rb +69 -0
- data/app/models/concerns/geo_concerns/metadata_extraction_helper.rb +28 -0
- data/app/models/concerns/geo_concerns/raster_file_behavior.rb +14 -0
- data/app/models/concerns/geo_concerns/raster_work_behavior.rb +82 -0
- data/app/models/concerns/geo_concerns/solr_document_behavior.rb +25 -0
- data/app/models/concerns/geo_concerns/vector_file_behavior.rb +14 -0
- data/app/models/concerns/geo_concerns/vector_work_behavior.rb +78 -0
- data/app/presenters/geo_concerns/geo_concerns_show_presenter.rb +30 -0
- data/app/presenters/geo_concerns/image_work_show_presenter.rb +18 -0
- data/app/presenters/geo_concerns/raster_work_show_presenter.rb +18 -0
- data/app/presenters/geo_concerns/vector_work_show_presenter.rb +10 -0
- data/app/processors/geo_concerns/processors/base_geo_processor.rb +86 -0
- data/app/processors/geo_concerns/processors/raster.rb +11 -0
- data/app/processors/geo_concerns/processors/raster/aig.rb +44 -0
- data/app/processors/geo_concerns/processors/raster/base.rb +74 -0
- data/app/processors/geo_concerns/processors/raster/dem.rb +46 -0
- data/app/processors/geo_concerns/processors/raster/processor.rb +27 -0
- data/app/processors/geo_concerns/processors/vector.rb +11 -0
- data/app/processors/geo_concerns/processors/vector/base.rb +68 -0
- data/app/processors/geo_concerns/processors/vector/processor.rb +25 -0
- data/app/processors/geo_concerns/processors/vector/shapefile.rb +20 -0
- data/app/processors/geo_concerns/processors/zip.rb +31 -0
- data/app/renderers/coverage_renderer.rb +34 -0
- data/app/runners/geo_concerns/runners/raster_derivatives.rb +9 -0
- data/app/runners/geo_concerns/runners/vector_derivatives.rb +9 -0
- data/app/schemas/geo_concerns/basic_geo_metadata_optional.rb +39 -0
- data/app/schemas/geo_concerns/basic_geo_metadata_required.rb +25 -0
- data/app/services/authority_service.rb +23 -0
- data/app/services/geo_concerns/derivative_path.rb +16 -0
- data/app/services/image_format_service.rb +4 -0
- data/app/services/metadata_format_service.rb +4 -0
- data/app/services/raster_format_service.rb +4 -0
- data/app/services/vector_format_service.rb +4 -0
- data/app/values/geo_concerns/coverage.rb +36 -0
- data/app/values/geo_concerns/time_period.rb +31 -0
- data/app/views/curation_concerns/file_sets/_form.html.erb +48 -0
- data/app/views/curation_concerns/image_works/_form.html.erb +23 -0
- data/app/views/curation_concerns/image_works/_image_work.html.erb +2 -0
- data/app/views/curation_concerns/image_works/_members.html.erb +30 -0
- data/app/views/curation_concerns/image_works/_related_image_files.html.erb +24 -0
- data/app/views/curation_concerns/image_works/_show_actions.html.erb +16 -0
- data/app/views/curation_concerns/image_works/show.html.erb +17 -0
- data/app/views/curation_concerns/raster_works/_form.html.erb +25 -0
- data/app/views/curation_concerns/raster_works/_members.html.erb +30 -0
- data/app/views/curation_concerns/raster_works/_raster_work.html.erb +2 -0
- data/app/views/curation_concerns/raster_works/_related_raster_files.html.erb +24 -0
- data/app/views/curation_concerns/raster_works/_show_actions.html.erb +16 -0
- data/app/views/curation_concerns/raster_works/show.html.erb +17 -0
- data/app/views/curation_concerns/vector_works/_form.html.erb +25 -0
- data/app/views/curation_concerns/vector_works/_related_vector_files.html.erb +24 -0
- data/app/views/curation_concerns/vector_works/_show_actions.html.erb +15 -0
- data/app/views/curation_concerns/vector_works/_vector_work.html.erb +2 -0
- data/app/views/curation_concerns/vector_works/show.html.erb +15 -0
- data/app/views/geo_concerns/_attribute_rows.html.erb +11 -0
- data/app/views/geo_concerns/_attributes.html.erb +13 -0
- data/app/views/geo_concerns/_form_additional_information.html.erb +11 -0
- data/app/views/geo_concerns/_form_bounding_box.html.erb +9 -0
- data/app/views/geo_concerns/_form_descriptive_fields.html.erb +9 -0
- data/app/views/geo_concerns/_form_files_and_links.html.erb +0 -0
- data/app/views/geo_concerns/_form_populate_metadata.html.erb +8 -0
- data/app/views/geo_concerns/_form_required_information.html.erb +12 -0
- data/app/views/geo_concerns/_form_supplementary_fields.html.erb +15 -0
- data/app/views/geo_concerns/_related_external_metadata_files.html.erb +24 -0
- data/app/vocabs/geo_concerns/geo_terms.rb +12 -0
- data/bin/rails +12 -0
- data/config/routes.rb +6 -0
- data/geo_concerns.gemspec +36 -0
- data/lib/generators/geo_concerns/install_generator.rb +119 -0
- data/lib/generators/geo_concerns/templates/actors/curation_concerns/image_work_actor.rb +4 -0
- data/lib/generators/geo_concerns/templates/actors/curation_concerns/raster_work_actor.rb +4 -0
- data/lib/generators/geo_concerns/templates/actors/curation_concerns/vector_work_actor.rb +4 -0
- data/lib/generators/geo_concerns/templates/config/authorities/image_formats.yml +5 -0
- data/lib/generators/geo_concerns/templates/config/authorities/metadata_formats.yml +7 -0
- data/lib/generators/geo_concerns/templates/config/authorities/raster_formats.yml +9 -0
- data/lib/generators/geo_concerns/templates/config/authorities/vector_formats.yml +5 -0
- data/lib/generators/geo_concerns/templates/controllers/curation_concerns/file_sets_controller.rb +6 -0
- data/lib/generators/geo_concerns/templates/controllers/curation_concerns/image_works_controller.rb +5 -0
- data/lib/generators/geo_concerns/templates/controllers/curation_concerns/raster_works_controller.rb +6 -0
- data/lib/generators/geo_concerns/templates/controllers/curation_concerns/vector_works_controller.rb +6 -0
- data/lib/generators/geo_concerns/templates/geo_concerns.js +1 -0
- data/lib/generators/geo_concerns/templates/geo_concerns.scss +3 -0
- data/lib/generators/geo_concerns/templates/jobs/characterize_job.rb +12 -0
- data/lib/generators/geo_concerns/templates/models/file_set.rb +4 -0
- data/lib/generators/geo_concerns/templates/models/image_work.rb +6 -0
- data/lib/generators/geo_concerns/templates/models/raster_work.rb +7 -0
- data/lib/generators/geo_concerns/templates/models/vector_work.rb +7 -0
- data/lib/generators/geo_concerns/templates/presenters/file_set_presenter.rb +3 -0
- data/lib/generators/geo_concerns/templates/spec/actor_spec.rb.erb +9 -0
- data/lib/generators/geo_concerns/templates/spec/controller_spec.rb.erb +9 -0
- data/lib/generators/geo_concerns/templates/spec/model_spec.rb.erb +9 -0
- data/lib/geo_concerns.rb +6 -0
- data/lib/geo_concerns/engine.rb +4 -0
- data/lib/geo_concerns/version.rb +3 -0
- data/lib/tasks/geo_concerns_tasks.rake +4 -0
- data/solr/config/_rest_managed.json +3 -0
- data/solr/config/admin-extra.html +31 -0
- data/solr/config/elevate.xml +36 -0
- data/solr/config/mapping-ISOLatin1Accent.txt +246 -0
- data/solr/config/protwords.txt +21 -0
- data/solr/config/schema.xml +372 -0
- data/solr/config/scripts.conf +24 -0
- data/solr/config/solrconfig.xml +312 -0
- data/solr/config/spellings.txt +2 -0
- data/solr/config/stopwords.txt +58 -0
- data/solr/config/stopwords_en.txt +58 -0
- data/solr/config/synonyms.txt +31 -0
- data/solr/config/xslt/example.xsl +132 -0
- data/solr/config/xslt/example_atom.xsl +67 -0
- data/solr/config/xslt/example_rss.xsl +66 -0
- data/solr/config/xslt/luke.xsl +337 -0
- data/spec/actors/geo_concerns/file_actor_spec.rb +26 -0
- data/spec/controllers/image_works_controller_spec.rb +25 -0
- data/spec/controllers/raster_works_controller_spec.rb +50 -0
- data/spec/controllers/vector_works_controller_spec.rb +50 -0
- data/spec/factories/external_metadata_files.rb +20 -0
- data/spec/factories/image_files.rb +32 -0
- data/spec/factories/image_works.rb +68 -0
- data/spec/factories/raster_files.rb +35 -0
- data/spec/factories/raster_works.rb +86 -0
- data/spec/factories/users.rb +26 -0
- data/spec/factories/vector_files.rb +31 -0
- data/spec/factories/vector_works.rb +83 -0
- data/spec/features/create_raster_work_spec.rb +49 -0
- data/spec/forms/geo_concerns/basic_geo_metadata_form_spec.rb +27 -0
- data/spec/forms/geo_concerns/external_metadata_file_form_spec.rb +27 -0
- data/spec/forms/geo_concerns/georeferenced_form_spec.rb +29 -0
- data/spec/forms/geo_concerns/image_work_form_spec.rb +11 -0
- data/spec/forms/geo_concerns/raster_work_form_spec.rb +15 -0
- data/spec/forms/geo_concerns/vector_work_form_spec.rb +15 -0
- data/spec/helpers/bounding_box_helper_spec.rb +34 -0
- data/spec/models/concerns/basic_geo_metadata_spec.rb +21 -0
- data/spec/models/concerns/geo_concerns/file_set/derivatives_spec.rb +108 -0
- data/spec/models/concerns/geo_concerns/file_set/geo_file_format_behavior_spec.rb +56 -0
- data/spec/models/external_metadata_file_spec.rb +118 -0
- data/spec/models/file_set_spec.rb +9 -0
- data/spec/models/image_file_spec.rb +48 -0
- data/spec/models/image_work_spec.rb +71 -0
- data/spec/models/raster_file_spec.rb +48 -0
- data/spec/models/raster_work_spec.rb +122 -0
- data/spec/models/solr_document_spec.rb +35 -0
- data/spec/models/vector_file_spec.rb +48 -0
- data/spec/models/vector_work_spec.rb +113 -0
- data/spec/presenters/file_set_presenter_spec.rb +13 -0
- data/spec/presenters/geo_concerns_show_presenter_spec.rb +56 -0
- data/spec/presenters/image_work_show_presenter_spec.rb +52 -0
- data/spec/presenters/raster_work_show_presenter_spec.rb +52 -0
- data/spec/presenters/vector_work_show_presenter_spec.rb +41 -0
- data/spec/processors/geo_concerns/processors/base_geo_processor_spec.rb +109 -0
- data/spec/processors/geo_concerns/processors/raster/aig_spec.rb +28 -0
- data/spec/processors/geo_concerns/processors/raster/base_spec.rb +86 -0
- data/spec/processors/geo_concerns/processors/raster/dem_spec.rb +26 -0
- data/spec/processors/geo_concerns/processors/raster/processor_spec.rb +39 -0
- data/spec/processors/geo_concerns/processors/vector/base_spec.rb +67 -0
- data/spec/processors/geo_concerns/processors/vector/processor_spec.rb +28 -0
- data/spec/processors/geo_concerns/processors/vector/shapefile_spec.rb +17 -0
- data/spec/processors/geo_concerns/processors/zip_spec.rb +39 -0
- data/spec/renderers/coverage_renderer_spec.rb +21 -0
- data/spec/services/derivative_path_spec.rb +12 -0
- data/spec/services/raster_format_service_spec.rb +13 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/controllers/engine_helpers.rb +7 -0
- data/spec/support/database_cleaner.rb +18 -0
- data/spec/support/devise.rb +10 -0
- data/spec/support/devise_helpers.rb +6 -0
- data/spec/support/factory_girl.rb +3 -0
- data/spec/support/features.rb +14 -0
- data/spec/support/features/session_helpers.rb +40 -0
- data/spec/support/fixture_reader.rb +7 -0
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +20 -0
- data/spec/values/coverage_spec.rb +40 -0
- data/tasks/ci.rake +49 -0
- metadata +527 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
function boundingBoxSelector(options) {
|
2
|
+
var inputId = options.inputId;
|
3
|
+
var initialBounds;
|
4
|
+
var coverage = options.coverage;
|
5
|
+
if (!coverage && inputId ) {
|
6
|
+
var coverage = $(inputId).val();
|
7
|
+
}
|
8
|
+
|
9
|
+
if (coverage) {
|
10
|
+
initialBounds = coverageToBounds(coverage);
|
11
|
+
} else {
|
12
|
+
initialBounds = L.latLngBounds([[-50, -100], [72, 100]]);
|
13
|
+
};
|
14
|
+
|
15
|
+
var map = L.map('bbox', {
|
16
|
+
maxBounds: [[-100, -180], [100, 180]],
|
17
|
+
touchZoom: false,
|
18
|
+
scrollWheelZoom: false
|
19
|
+
}).fitBounds(initialBounds);
|
20
|
+
|
21
|
+
L.tileLayer('https://otile1-s.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
|
22
|
+
maxZoom: 18
|
23
|
+
}).addTo(map);
|
24
|
+
L.Control.geocoder({ position: 'topleft' }).addTo(map);
|
25
|
+
|
26
|
+
if (options.readonly) {
|
27
|
+
new L.Rectangle(initialBounds, { color: 'white', weight: 2, opacity: 0.9 }).addTo(map);
|
28
|
+
} else {
|
29
|
+
boundingBox = new L.BoundingBox({ bounds: initialBounds,
|
30
|
+
buttonPosition: 'topright', }).addTo(map);
|
31
|
+
boundingBox.on('change', function() {
|
32
|
+
$(inputId).val(boundsToCoverage(this.getBounds()));
|
33
|
+
});
|
34
|
+
|
35
|
+
boundingBox.on('change', function() {
|
36
|
+
$(inputId).val(boundsToCoverage(this.getBounds()));
|
37
|
+
});
|
38
|
+
|
39
|
+
boundingBox.enable();
|
40
|
+
}
|
41
|
+
};
|
42
|
+
|
43
|
+
function clampBounds(bounds) {
|
44
|
+
try {
|
45
|
+
n = valBetween(bounds.getNorth(), -90, 90);
|
46
|
+
e = valBetween(bounds.getEast(), -180, 180);
|
47
|
+
s = valBetween(bounds.getSouth(), -90, 90);
|
48
|
+
w = valBetween(bounds.getWest(), -180, 180);
|
49
|
+
return L.latLngBounds([s, w], [n, e]);
|
50
|
+
}
|
51
|
+
catch (err) {
|
52
|
+
return null;
|
53
|
+
}
|
54
|
+
};
|
55
|
+
|
56
|
+
function valBetween(val, min, max) {
|
57
|
+
return (Math.min(max, Math.max(min, val)));
|
58
|
+
};
|
59
|
+
|
60
|
+
function coverageToBounds(coverage) {
|
61
|
+
try {
|
62
|
+
n = String(coverage).match(/northlimit=([\.\d\-]+)/m);
|
63
|
+
e = String(coverage).match(/eastlimit=([\.\d\-]+)/m);
|
64
|
+
s = String(coverage).match(/southlimit=([\.\d\-]+)/m);
|
65
|
+
w = String(coverage).match(/westlimit=([\.\d\-]+)/m);
|
66
|
+
|
67
|
+
if (n && e && s && w) {
|
68
|
+
return L.latLngBounds([s[1], w[1]], [n[1], e[1]]);
|
69
|
+
} else {
|
70
|
+
return null;
|
71
|
+
}
|
72
|
+
}
|
73
|
+
catch (err) {
|
74
|
+
return null;
|
75
|
+
}
|
76
|
+
};
|
77
|
+
|
78
|
+
function boundsToCoverage(bounds) {
|
79
|
+
try {
|
80
|
+
bounds = clampBounds(bounds);
|
81
|
+
n = bounds.getNorth().toFixed(6);
|
82
|
+
e = bounds.getEast().toFixed(6);
|
83
|
+
s = bounds.getSouth().toFixed(6);
|
84
|
+
w = bounds.getWest().toFixed(6);
|
85
|
+
|
86
|
+
if (n && e && s && w) {
|
87
|
+
return 'northlimit=' + n + '; ' +
|
88
|
+
'eastlimit=' + e + '; ' +
|
89
|
+
'southlimit=' + s + '; ' +
|
90
|
+
'westlimit=' + w + '; ' +
|
91
|
+
'units=degrees; ' +
|
92
|
+
'projection=EPSG:4326';
|
93
|
+
} else {
|
94
|
+
return '';
|
95
|
+
}
|
96
|
+
}
|
97
|
+
catch (err) {
|
98
|
+
return '';
|
99
|
+
}
|
100
|
+
};
|
@@ -0,0 +1,467 @@
|
|
1
|
+
/*
|
2
|
+
* Leaflet.boundingbox (Modified from Leaflet.locationfilter)
|
3
|
+
* Copyright (C) 2012, Tripbirds.com
|
4
|
+
* Copyright (C) 2014, Eliot Jordan
|
5
|
+
* Licensed under the MIT License.
|
6
|
+
*/
|
7
|
+
|
8
|
+
L.LatLngBounds.prototype.modify = function(map, amount) {
|
9
|
+
var sw = this.getSouthWest(),
|
10
|
+
ne = this.getNorthEast(),
|
11
|
+
swPoint = map.latLngToLayerPoint(sw),
|
12
|
+
nePoint = map.latLngToLayerPoint(ne);
|
13
|
+
|
14
|
+
sw = map.layerPointToLatLng(new L.Point(swPoint.x-amount, swPoint.y+amount));
|
15
|
+
ne = map.layerPointToLatLng(new L.Point(nePoint.x+amount, nePoint.y-amount));
|
16
|
+
|
17
|
+
return new L.LatLngBounds(sw, ne);
|
18
|
+
};
|
19
|
+
|
20
|
+
L.Control.Button = L.Class.extend({
|
21
|
+
initialize: function(options) {
|
22
|
+
L.Util.setOptions(this, options);
|
23
|
+
},
|
24
|
+
|
25
|
+
addTo: function(container) {
|
26
|
+
container.addButton(this);
|
27
|
+
return this;
|
28
|
+
},
|
29
|
+
|
30
|
+
onAdd: function (buttonContainer) {
|
31
|
+
this._buttonContainer = buttonContainer;
|
32
|
+
this._button = L.DomUtil.create('a', this.options.className, this._buttonContainer.getContainer());
|
33
|
+
this._button.href = '#';
|
34
|
+
this.setText(this.options.text);
|
35
|
+
|
36
|
+
var that = this;
|
37
|
+
this._onClick = function(event) {
|
38
|
+
that.options.onClick.call(that, event);
|
39
|
+
};
|
40
|
+
|
41
|
+
L.DomEvent
|
42
|
+
.on(this._button, 'click', L.DomEvent.stopPropagation)
|
43
|
+
.on(this._button, 'mousedown', L.DomEvent.stopPropagation)
|
44
|
+
.on(this._button, 'dblclick', L.DomEvent.stopPropagation)
|
45
|
+
.on(this._button, 'click', L.DomEvent.preventDefault)
|
46
|
+
.on(this._button, 'click', this._onClick, this);
|
47
|
+
},
|
48
|
+
|
49
|
+
remove: function() {
|
50
|
+
L.DomEvent.off(this._button, "click", this._onClick);
|
51
|
+
this._buttonContainer.getContainer().removeChild(this._button);
|
52
|
+
},
|
53
|
+
|
54
|
+
setText: function(text) {
|
55
|
+
this._button.title = text;
|
56
|
+
this._button.innerHTML = text;
|
57
|
+
}
|
58
|
+
});
|
59
|
+
|
60
|
+
L.Control.ButtonContainer = L.Control.extend({
|
61
|
+
options: {
|
62
|
+
position: 'topright'
|
63
|
+
},
|
64
|
+
|
65
|
+
getContainer: function() {
|
66
|
+
if (!this._container) {
|
67
|
+
this._container = L.DomUtil.create('div', this.options.className);
|
68
|
+
}
|
69
|
+
return this._container;
|
70
|
+
},
|
71
|
+
|
72
|
+
onAdd: function (map) {
|
73
|
+
this._map = map;
|
74
|
+
return this.getContainer();
|
75
|
+
},
|
76
|
+
|
77
|
+
addButton: function(button) {
|
78
|
+
button.onAdd(this);
|
79
|
+
},
|
80
|
+
|
81
|
+
addClass: function(className) {
|
82
|
+
L.DomUtil.addClass(this.getContainer(), className);
|
83
|
+
},
|
84
|
+
|
85
|
+
removeClass: function(className) {
|
86
|
+
L.DomUtil.removeClass(this.getContainer(), className);
|
87
|
+
}
|
88
|
+
});
|
89
|
+
|
90
|
+
L.BoundingBox = L.Class.extend({
|
91
|
+
includes: L.Mixin.Events,
|
92
|
+
|
93
|
+
options: {
|
94
|
+
adjustButton: {
|
95
|
+
text: "Select Area"
|
96
|
+
},
|
97
|
+
buttonPosition: 'topright'
|
98
|
+
},
|
99
|
+
|
100
|
+
initialize: function(options) {
|
101
|
+
L.Util.setOptions(this, options);
|
102
|
+
},
|
103
|
+
|
104
|
+
addTo: function(map) {
|
105
|
+
map.addLayer(this);
|
106
|
+
return this;
|
107
|
+
},
|
108
|
+
|
109
|
+
onAdd: function(map) {
|
110
|
+
this._map = map;
|
111
|
+
|
112
|
+
if (this.options.adjustButton) {
|
113
|
+
this._initializeButtonContainer();
|
114
|
+
}
|
115
|
+
|
116
|
+
if (this.options.enable) {
|
117
|
+
this.enable();
|
118
|
+
}
|
119
|
+
},
|
120
|
+
|
121
|
+
onRemove: function(map) {
|
122
|
+
this.disable();
|
123
|
+
if (this._buttonContainer) {
|
124
|
+
this._buttonContainer.removeFrom(map);
|
125
|
+
}
|
126
|
+
},
|
127
|
+
|
128
|
+
/* Get the current filter bounds */
|
129
|
+
getBounds: function() {
|
130
|
+
return new L.LatLngBounds(this._sw, this._ne);
|
131
|
+
},
|
132
|
+
|
133
|
+
setBounds: function(bounds) {
|
134
|
+
this._nw = bounds.getNorthWest();
|
135
|
+
this._ne = bounds.getNorthEast();
|
136
|
+
this._sw = bounds.getSouthWest();
|
137
|
+
this._se = bounds.getSouthEast();
|
138
|
+
if (this.isEnabled()) {
|
139
|
+
this._draw();
|
140
|
+
this.fire("change", {bounds: bounds});
|
141
|
+
}
|
142
|
+
},
|
143
|
+
|
144
|
+
_setBounds: function(bounds) {
|
145
|
+
this.setBounds(bounds);
|
146
|
+
this._map.fitBounds(bounds);
|
147
|
+
},
|
148
|
+
|
149
|
+
isEnabled: function() {
|
150
|
+
return this._enabled;
|
151
|
+
},
|
152
|
+
|
153
|
+
/* Draw a rectangle */
|
154
|
+
_drawRectangle: function(bounds, options) {
|
155
|
+
options = options || {};
|
156
|
+
var defaultOptions = {
|
157
|
+
stroke: false,
|
158
|
+
fill: true,
|
159
|
+
fillColor: "black",
|
160
|
+
fillOpacity: 0.3,
|
161
|
+
clickable: false
|
162
|
+
};
|
163
|
+
options = L.Util.extend(defaultOptions, options);
|
164
|
+
var rect = new L.Rectangle(bounds, options);
|
165
|
+
rect.addTo(this._layer);
|
166
|
+
return rect;
|
167
|
+
},
|
168
|
+
|
169
|
+
/* Draw a draggable marker */
|
170
|
+
_drawImageMarker: function(point, options) {
|
171
|
+
var marker = new L.Marker(point, {
|
172
|
+
icon: new L.DivIcon({
|
173
|
+
iconAnchor: options.anchor,
|
174
|
+
iconSize: options.size,
|
175
|
+
className: options.className
|
176
|
+
}),
|
177
|
+
draggable: true
|
178
|
+
});
|
179
|
+
marker.addTo(this._layer);
|
180
|
+
return marker;
|
181
|
+
},
|
182
|
+
|
183
|
+
/* Draw a move marker. Sets up drag listener that updates the
|
184
|
+
filter corners and redraws the filter when the move marker is
|
185
|
+
moved */
|
186
|
+
_drawMoveMarker: function(point) {
|
187
|
+
var that = this;
|
188
|
+
this._moveMarker = this._drawImageMarker(point, {
|
189
|
+
"className": "location-filter move-marker",
|
190
|
+
"anchor": [-10, -10],
|
191
|
+
"size": [13,13]
|
192
|
+
});
|
193
|
+
this._moveMarker.on('drag', function(e) {
|
194
|
+
var markerPos = that._moveMarker.getLatLng(),
|
195
|
+
latDelta = markerPos.lat-that._nw.lat,
|
196
|
+
lngDelta = markerPos.lng-that._nw.lng;
|
197
|
+
that._nw = new L.LatLng(that._nw.lat+latDelta, that._nw.lng+lngDelta, true);
|
198
|
+
that._ne = new L.LatLng(that._ne.lat+latDelta, that._ne.lng+lngDelta, true);
|
199
|
+
that._sw = new L.LatLng(that._sw.lat+latDelta, that._sw.lng+lngDelta, true);
|
200
|
+
that._se = new L.LatLng(that._se.lat+latDelta, that._se.lng+lngDelta, true);
|
201
|
+
that._draw();
|
202
|
+
});
|
203
|
+
this._setupDragendListener(this._moveMarker);
|
204
|
+
return this._moveMarker;
|
205
|
+
},
|
206
|
+
|
207
|
+
/* Draw a resize marker */
|
208
|
+
_drawResizeMarker: function(point, latFollower, lngFollower, otherPos) {
|
209
|
+
return this._drawImageMarker(point, {
|
210
|
+
"className": "location-filter resize-marker",
|
211
|
+
"anchor": [7, 6],
|
212
|
+
"size": [13, 12]
|
213
|
+
});
|
214
|
+
},
|
215
|
+
|
216
|
+
/* Track moving of the given resize marker and update the markers
|
217
|
+
given in options.moveAlong to match the position of the moved
|
218
|
+
marker. Update filter corners and redraw the filter */
|
219
|
+
_setupResizeMarkerTracking: function(marker, options) {
|
220
|
+
var that = this;
|
221
|
+
marker.on('drag', function(e) {
|
222
|
+
var curPosition = marker.getLatLng(),
|
223
|
+
latMarker = options.moveAlong.lat,
|
224
|
+
lngMarker = options.moveAlong.lng;
|
225
|
+
// Move follower markers when this marker is moved
|
226
|
+
latMarker.setLatLng(new L.LatLng(curPosition.lat, latMarker.getLatLng().lng, true));
|
227
|
+
lngMarker.setLatLng(new L.LatLng(lngMarker.getLatLng().lat, curPosition.lng, true));
|
228
|
+
// Sort marker positions in nw, ne, sw, se order
|
229
|
+
var corners = [that._nwMarker.getLatLng(),
|
230
|
+
that._neMarker.getLatLng(),
|
231
|
+
that._swMarker.getLatLng(),
|
232
|
+
that._seMarker.getLatLng()];
|
233
|
+
corners.sort(function(a, b) {
|
234
|
+
if (a.lat != b.lat)
|
235
|
+
return b.lat-a.lat;
|
236
|
+
else
|
237
|
+
return a.lng-b.lng;
|
238
|
+
});
|
239
|
+
// Update corner points and redraw everything except the resize markers
|
240
|
+
that._nw = corners[0];
|
241
|
+
that._ne = corners[1];
|
242
|
+
that._sw = corners[2];
|
243
|
+
that._se = corners[3];
|
244
|
+
that._draw({repositionResizeMarkers: false});
|
245
|
+
});
|
246
|
+
this._setupDragendListener(marker);
|
247
|
+
},
|
248
|
+
|
249
|
+
/* Emit a change event whenever dragend is triggered on the
|
250
|
+
given marker */
|
251
|
+
_setupDragendListener: function(marker) {
|
252
|
+
var that = this;
|
253
|
+
marker.on('dragend', function(e) {
|
254
|
+
that.fire("change", {bounds: that.getBounds()});
|
255
|
+
});
|
256
|
+
},
|
257
|
+
|
258
|
+
/* Create bounds for the mask rectangles and the location
|
259
|
+
filter rectangle */
|
260
|
+
_calculateBounds: function() {
|
261
|
+
var mapBounds = this._map.getBounds(),
|
262
|
+
outerBounds = new L.LatLngBounds(
|
263
|
+
new L.LatLng(mapBounds.getSouthWest().lat-0.1,
|
264
|
+
mapBounds.getSouthWest().lng-0.1, true),
|
265
|
+
new L.LatLng(mapBounds.getNorthEast().lat+0.1,
|
266
|
+
mapBounds.getNorthEast().lng+0.1, true)
|
267
|
+
);
|
268
|
+
|
269
|
+
// The south west and north east points of the mask */
|
270
|
+
this._osw = outerBounds.getSouthWest();
|
271
|
+
this._one = outerBounds.getNorthEast();
|
272
|
+
|
273
|
+
// Bounds for the mask rectangles
|
274
|
+
this._northBounds = new L.LatLngBounds(new L.LatLng(this._ne.lat, this._osw.lng, true), this._one);
|
275
|
+
this._westBounds = new L.LatLngBounds(new L.LatLng(this._sw.lat, this._osw.lng, true), this._nw);
|
276
|
+
this._eastBounds = new L.LatLngBounds(this._se, new L.LatLng(this._ne.lat, this._one.lng, true));
|
277
|
+
this._southBounds = new L.LatLngBounds(this._osw, new L.LatLng(this._sw.lat, this._one.lng, true));
|
278
|
+
},
|
279
|
+
|
280
|
+
/* Initializes rectangles and markers */
|
281
|
+
_initialDraw: function() {
|
282
|
+
if (this._initialDrawCalled) {
|
283
|
+
return;
|
284
|
+
}
|
285
|
+
|
286
|
+
this._layer = new L.LayerGroup();
|
287
|
+
|
288
|
+
// Calculate filter bounds
|
289
|
+
this._calculateBounds();
|
290
|
+
|
291
|
+
// Create rectangles
|
292
|
+
this._northRect = this._drawRectangle(this._northBounds);
|
293
|
+
this._westRect = this._drawRectangle(this._westBounds);
|
294
|
+
this._eastRect = this._drawRectangle(this._eastBounds);
|
295
|
+
this._southRect = this._drawRectangle(this._southBounds);
|
296
|
+
this._innerRect = this._drawRectangle(this.getBounds(), {
|
297
|
+
fillOpacity: 0,
|
298
|
+
stroke: true,
|
299
|
+
color: "white",
|
300
|
+
weight: 1,
|
301
|
+
opacity: 0.9
|
302
|
+
});
|
303
|
+
|
304
|
+
// Create resize markers
|
305
|
+
this._nwMarker = this._drawResizeMarker(this._nw);
|
306
|
+
this._neMarker = this._drawResizeMarker(this._ne);
|
307
|
+
this._swMarker = this._drawResizeMarker(this._sw);
|
308
|
+
this._seMarker = this._drawResizeMarker(this._se);
|
309
|
+
|
310
|
+
// Setup tracking of resize markers. Each marker has pair of
|
311
|
+
// follower markers that must be moved whenever the marker is
|
312
|
+
// moved. For example, whenever the north west resize marker
|
313
|
+
// moves, the south west marker must move along on the x-axis
|
314
|
+
// and the north east marker must move on the y axis
|
315
|
+
this._setupResizeMarkerTracking(this._nwMarker, {moveAlong: {lat: this._neMarker, lng: this._swMarker}});
|
316
|
+
this._setupResizeMarkerTracking(this._neMarker, {moveAlong: {lat: this._nwMarker, lng: this._seMarker}});
|
317
|
+
this._setupResizeMarkerTracking(this._swMarker, {moveAlong: {lat: this._seMarker, lng: this._nwMarker}});
|
318
|
+
this._setupResizeMarkerTracking(this._seMarker, {moveAlong: {lat: this._swMarker, lng: this._neMarker}});
|
319
|
+
|
320
|
+
// Create move marker
|
321
|
+
this._moveMarker = this._drawMoveMarker(this._nw);
|
322
|
+
|
323
|
+
this._initialDrawCalled = true;
|
324
|
+
},
|
325
|
+
|
326
|
+
/* Reposition all rectangles and markers to the current filter bounds. */
|
327
|
+
_draw: function(options) {
|
328
|
+
options = L.Util.extend({repositionResizeMarkers: true}, options);
|
329
|
+
|
330
|
+
// Calculate filter bounds
|
331
|
+
this._calculateBounds();
|
332
|
+
|
333
|
+
// Reposition rectangles
|
334
|
+
this._northRect.setBounds(this._northBounds);
|
335
|
+
this._westRect.setBounds(this._westBounds);
|
336
|
+
this._eastRect.setBounds(this._eastBounds);
|
337
|
+
this._southRect.setBounds(this._southBounds);
|
338
|
+
this._innerRect.setBounds(this.getBounds());
|
339
|
+
|
340
|
+
// Reposition resize markers
|
341
|
+
if (options.repositionResizeMarkers) {
|
342
|
+
this._nwMarker.setLatLng(this._nw);
|
343
|
+
this._neMarker.setLatLng(this._ne);
|
344
|
+
this._swMarker.setLatLng(this._sw);
|
345
|
+
this._seMarker.setLatLng(this._se);
|
346
|
+
}
|
347
|
+
|
348
|
+
// Reposition the move marker
|
349
|
+
this._moveMarker.setLatLng(this._nw);
|
350
|
+
},
|
351
|
+
|
352
|
+
/* Adjust the location filter to the current map bounds */
|
353
|
+
_adjustToMap: function() {
|
354
|
+
this.setBounds(this._map.getBounds());
|
355
|
+
this._map.zoomOut();
|
356
|
+
},
|
357
|
+
|
358
|
+
/* Enable the location filter */
|
359
|
+
enable: function() {
|
360
|
+
if (this._enabled) {
|
361
|
+
return;
|
362
|
+
}
|
363
|
+
|
364
|
+
// Initialize corners
|
365
|
+
var bounds;
|
366
|
+
if (this._sw && this._ne) {
|
367
|
+
bounds = new L.LatLngBounds(this._sw, this._ne);
|
368
|
+
} else if (this.options.bounds) {
|
369
|
+
bounds = this.options.bounds;
|
370
|
+
} else {
|
371
|
+
bounds = this._map.getBounds();
|
372
|
+
}
|
373
|
+
this._map.invalidateSize();
|
374
|
+
this._nw = bounds.getNorthWest();
|
375
|
+
this._ne = bounds.getNorthEast();
|
376
|
+
this._sw = bounds.getSouthWest();
|
377
|
+
this._se = bounds.getSouthEast();
|
378
|
+
|
379
|
+
|
380
|
+
// Update buttons
|
381
|
+
if (this._buttonContainer) {
|
382
|
+
this._buttonContainer.addClass("enabled");
|
383
|
+
}
|
384
|
+
|
385
|
+
if (this.options.adjustButton) {
|
386
|
+
this._createAdjustButton();
|
387
|
+
}
|
388
|
+
|
389
|
+
// Draw filter
|
390
|
+
this._initialDraw();
|
391
|
+
this._draw();
|
392
|
+
|
393
|
+
// Set up map move event listener
|
394
|
+
var that = this;
|
395
|
+
this._moveHandler = function() {
|
396
|
+
that._draw();
|
397
|
+
};
|
398
|
+
this._map.on("move", this._moveHandler);
|
399
|
+
|
400
|
+
// Add the filter layer to the map
|
401
|
+
this._layer.addTo(this._map);
|
402
|
+
|
403
|
+
// Zoom out the map if necessary
|
404
|
+
var mapBounds = this._map.getBounds();
|
405
|
+
bounds = new L.LatLngBounds(this._sw, this._ne).modify(this._map, 10);
|
406
|
+
if (!mapBounds.contains(bounds.getSouthWest()) || !mapBounds.contains(bounds.getNorthEast())) {
|
407
|
+
this._map.fitBounds(bounds);
|
408
|
+
}
|
409
|
+
|
410
|
+
this._enabled = true;
|
411
|
+
|
412
|
+
// Fire the enabled event
|
413
|
+
this.fire("enabled");
|
414
|
+
},
|
415
|
+
|
416
|
+
/* Disable the location filter */
|
417
|
+
disable: function() {
|
418
|
+
if (!this._enabled) {
|
419
|
+
return;
|
420
|
+
}
|
421
|
+
|
422
|
+
// Update buttons
|
423
|
+
if (this._buttonContainer) {
|
424
|
+
this._buttonContainer.removeClass("enabled");
|
425
|
+
}
|
426
|
+
|
427
|
+
if (this._adjustButton) {
|
428
|
+
this._adjustButton.remove();
|
429
|
+
}
|
430
|
+
|
431
|
+
// Remove event listener
|
432
|
+
this._map.off("move", this._moveHandler);
|
433
|
+
|
434
|
+
// Remove rectangle layer from map
|
435
|
+
this._map.removeLayer(this._layer);
|
436
|
+
|
437
|
+
this._enabled = false;
|
438
|
+
|
439
|
+
// Fire the disabled event
|
440
|
+
this.fire("disabled");
|
441
|
+
},
|
442
|
+
|
443
|
+
/* Create a button that allows the user to adjust the location
|
444
|
+
filter to the current zoom */
|
445
|
+
_createAdjustButton: function() {
|
446
|
+
var that = this;
|
447
|
+
this._adjustButton = new L.Control.Button({
|
448
|
+
className: "adjust-button",
|
449
|
+
text: this.options.adjustButton.text,
|
450
|
+
|
451
|
+
onClick: function(event) {
|
452
|
+
that._adjustToMap();
|
453
|
+
that.fire("adjustToZoomClick");
|
454
|
+
}
|
455
|
+
}).addTo(this._buttonContainer);
|
456
|
+
},
|
457
|
+
|
458
|
+
// Create the button container
|
459
|
+
_initializeButtonContainer: function() {
|
460
|
+
var that = this;
|
461
|
+
this._buttonContainer = new L.Control.ButtonContainer({
|
462
|
+
className: "location-filter button-container leaflet-bar",
|
463
|
+
position: this.options.buttonPosition
|
464
|
+
});
|
465
|
+
this._buttonContainer.addTo(this._map);
|
466
|
+
}
|
467
|
+
});
|