blacklight-maps 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 +20 -0
- data/.travis.yml +18 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +13 -0
- data/README.md +81 -0
- data/Rakefile +43 -0
- data/app/assets/javascripts/blacklight-maps.js +8 -0
- data/app/assets/javascripts/blacklight-maps/blacklight-maps-browse.js +141 -0
- data/app/assets/stylesheets/blacklight_maps/blacklight-maps.css.scss +4 -0
- data/app/assets/stylesheets/blacklight_maps/default.css.scss +24 -0
- data/app/helpers/blacklight_maps_helper.rb +36 -0
- data/app/views/catalog/_document_maps.html.erb +6 -0
- data/app/views/catalog/_index_maps.html.erb +9 -0
- data/blacklight-maps.gemspec +34 -0
- data/config/jetty.yml +7 -0
- data/config/locales/blacklight-maps.en.yml +5 -0
- data/config/routes.rb +4 -0
- data/docs/map-sidebar.png +0 -0
- data/docs/map-view.png +0 -0
- data/lib/blacklight/maps.rb +7 -0
- data/lib/blacklight/maps/engine.rb +32 -0
- data/lib/blacklight/maps/version.rb +5 -0
- data/lib/generators/blacklight_maps/install_generator.rb +25 -0
- data/lib/generators/blacklight_maps/templates/blacklight_maps.css.scss +3 -0
- data/lib/railties/blacklight_maps.rake +13 -0
- data/solr_conf/conf/schema.xml +673 -0
- data/solr_conf/conf/solrconfig.xml +523 -0
- data/spec/features/maps_spec.rb +79 -0
- data/spec/fixtures/sample_solr_documents.yml +2742 -0
- data/spec/helpers/blacklight_maps_helper_spec.rb +28 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/test_app_templates/Gemfile.extra +7 -0
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +23 -0
- metadata +268 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e35e471feb601eeeec9355dc1cc7e31d158f03bb
|
4
|
+
data.tar.gz: 8be5024c30a03decfb0e15563f79117606be1fec
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b019eae752da2b6cc576a759b09abb1d7799748c82603b0d13f20990f592e0ad51b35785abb6dda9370d5cbbd477c506ee26db9f73ae2cfa8aa7380ea584c707
|
7
|
+
data.tar.gz: a999abc043657b6f52ae34f1ce6d5479491b49812e2fa87b93257a3173de069a4e237d09e4cfb53869849d939803554842a918aec59e78c182d94be3d02f787b
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
notifications:
|
2
|
+
email: false
|
3
|
+
|
4
|
+
rvm:
|
5
|
+
- 2.1.0
|
6
|
+
- 2.0.0
|
7
|
+
- 1.9.3
|
8
|
+
- jruby-19mode
|
9
|
+
|
10
|
+
notifications:
|
11
|
+
irc: "irc.freenode.org#blacklight"
|
12
|
+
email:
|
13
|
+
- blacklight-commits@googlegroups.com
|
14
|
+
|
15
|
+
env:
|
16
|
+
global:
|
17
|
+
- JRUBY_OPTS="-J-Xms512m -J-Xmx1024m"
|
18
|
+
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
|
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in blacklight-maps.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'simplecov', require: false
|
7
|
+
gem 'coveralls', require: false
|
8
|
+
|
9
|
+
gem 'engine_cart', git: 'https://github.com/cbeer/engine_cart'
|
10
|
+
|
11
|
+
|
12
|
+
file = File.expand_path("Gemfile", ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path("../spec/internal", __FILE__))
|
13
|
+
if File.exists?(file)
|
14
|
+
puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
|
15
|
+
instance_eval File.read(file)
|
16
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2014 The Board of Trustees of the Leland Stanford Junior University.
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Blacklight::Maps
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/sul-dlss/blacklight-maps.png?branch=master)](https://travis-ci.org/sul-dlss/blacklight-maps)
|
4
|
+
|
5
|
+
Provides a map view for Blacklight search results.
|
6
|
+
|
7
|
+
![Screen shot](docs/map-view.png)
|
8
|
+
![Screen shot](docs/map-sidebar.png)
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'blacklight-maps'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install blacklight-maps
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
Blacklight-Maps adds a map view capability for a results set that contains geospatial coordinates (latitude/longitude).
|
27
|
+
|
28
|
+
For now, Blacklight-Maps requires that your SOLR index includes a field containing placenames with latitude and longitude coordinates delimited by `|`. This field can be multivalued.
|
29
|
+
|
30
|
+
A document requires the following field:
|
31
|
+
```
|
32
|
+
placename_coords:
|
33
|
+
- China|35.86166|104.195397
|
34
|
+
- Tibet|29.646923|91.117212
|
35
|
+
- India|20.593684|78.96288
|
36
|
+
```
|
37
|
+
|
38
|
+
Note: We are looking at implementing support for additional fields.
|
39
|
+
|
40
|
+
### Configuration
|
41
|
+
|
42
|
+
#### Required
|
43
|
+
Blacklight-Maps expects you to provide:
|
44
|
+
|
45
|
+
- a field to map the placename coordinates (`placename_coords` in the example above)
|
46
|
+
|
47
|
+
#### Optional
|
48
|
+
|
49
|
+
- the maxZoom [property of the map](http://leafletjs.com/reference.html#map-maxzoom)
|
50
|
+
- a [tileLayer url](http://leafletjs.com/reference.html#tilelayer-l.tilelayer) to change the basemap
|
51
|
+
- an [attribution string](http://leafletjs.com/reference.html#tilelayer-attribution) to describe the basemap layer
|
52
|
+
|
53
|
+
|
54
|
+
All of these options can easily be configured in `CatalogController.rb` in the `config` block.
|
55
|
+
|
56
|
+
```
|
57
|
+
...
|
58
|
+
configure_blacklight do |config|
|
59
|
+
## Default parameters to send to solr for all search-like requests. See also SolrHelper#solr_search_params
|
60
|
+
config.default_solr_params = {
|
61
|
+
:qt => 'search',
|
62
|
+
:rows => 10,
|
63
|
+
:fl => '*'
|
64
|
+
}
|
65
|
+
|
66
|
+
## Default values
|
67
|
+
config.view.maps.placename_coords_field = "placename_coords"
|
68
|
+
config.view.maps.tileurl = "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
69
|
+
config.view.maps.attribution = 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'
|
70
|
+
...
|
71
|
+
|
72
|
+
```
|
73
|
+
|
74
|
+
|
75
|
+
## Contributing
|
76
|
+
|
77
|
+
1. Fork it ( http://github.com/<my-github-username>/blacklight-maps/fork )
|
78
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
79
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
80
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
81
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
ZIP_URL = "https://github.com/projectblacklight/blacklight-jetty/archive/v4.6.0.zip"
|
4
|
+
APP_ROOT = File.dirname(__FILE__)
|
5
|
+
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
require 'engine_cart/rake_task'
|
8
|
+
|
9
|
+
require 'jettywrapper'
|
10
|
+
|
11
|
+
task default: :ci
|
12
|
+
|
13
|
+
RSpec::Core::RakeTask.new(:spec)
|
14
|
+
|
15
|
+
desc "Load fixtures"
|
16
|
+
task :fixtures => ['engine_cart:generate'] do
|
17
|
+
EngineCart.within_test_app do
|
18
|
+
system "rake blacklight_maps:solr:seed RAILS_ENV=test"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Execute Continuous Integration build"
|
23
|
+
task :ci => ['engine_cart:generate', 'jetty:clean', 'blacklight_maps:configure_jetty'] do
|
24
|
+
|
25
|
+
require 'jettywrapper'
|
26
|
+
jetty_params = Jettywrapper.load_config('test')
|
27
|
+
|
28
|
+
error = Jettywrapper.wrap(jetty_params) do
|
29
|
+
Rake::Task['fixtures'].invoke
|
30
|
+
Rake::Task['spec'].invoke
|
31
|
+
end
|
32
|
+
raise "test failures: #{error}" if error
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
namespace :blacklight_maps do
|
37
|
+
desc "Copies the default SOLR config for the bundled Testing Server"
|
38
|
+
task :configure_jetty do
|
39
|
+
FileList['solr_conf/conf/*'].each do |f|
|
40
|
+
cp("#{f}", 'jetty/solr/blacklight-core/conf/', :verbose => true)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
var map, sidebar;
|
2
|
+
|
3
|
+
Blacklight.onLoad(function() {
|
4
|
+
|
5
|
+
// Stop doing stuff if the map div isn't there
|
6
|
+
if ($("#blacklight-map").length === 0){
|
7
|
+
return;
|
8
|
+
}
|
9
|
+
|
10
|
+
// Get the configuration options from the data-attributes
|
11
|
+
$.extend(Blacklight.mapOptions, $("#blacklight-map").data());
|
12
|
+
|
13
|
+
map = L.map('blacklight-map').setView([0,0], 2);
|
14
|
+
L.tileLayer(Blacklight.mapOptions.tileurl, {
|
15
|
+
attribution: Blacklight.mapOptions.mapattribution,
|
16
|
+
maxZoom: Blacklight.mapOptions.maxzoom
|
17
|
+
}).addTo(map);
|
18
|
+
|
19
|
+
// Sets up leaflet-sidebar
|
20
|
+
sidebar = L.control.sidebar('blacklight-map-sidebar', {
|
21
|
+
position: 'right',
|
22
|
+
autoPan: false
|
23
|
+
});
|
24
|
+
|
25
|
+
// Adds leaflet-sidebar control to map (object)
|
26
|
+
map.addControl(sidebar);
|
27
|
+
|
28
|
+
// Create a marker cluster object and set options
|
29
|
+
markers = new L.MarkerClusterGroup({
|
30
|
+
showCoverageOnHover: false,
|
31
|
+
spiderfyOnMaxZoom: false,
|
32
|
+
singleMarkerMode: true,
|
33
|
+
animateAddingMarkers: true
|
34
|
+
});
|
35
|
+
|
36
|
+
geoJsonLayer = L.geoJson(geojson_docs, {
|
37
|
+
onEachFeature: function(feature, layer){
|
38
|
+
layer.defaultOptions.title = feature.properties.placename;
|
39
|
+
layer.on('click', function(e){
|
40
|
+
if (sidebar.isVisible()){
|
41
|
+
sidebar.hide();
|
42
|
+
}
|
43
|
+
var placenames = {};
|
44
|
+
placenames[feature.properties.placename] = [feature.properties.html];
|
45
|
+
offsetMap(e);
|
46
|
+
$('#blacklight-map-sidebar').html(buildList(placenames));
|
47
|
+
sidebar.show();
|
48
|
+
});
|
49
|
+
}
|
50
|
+
});
|
51
|
+
|
52
|
+
// Add GeoJSON layer to marker cluster object
|
53
|
+
markers.addLayer(geoJsonLayer);
|
54
|
+
|
55
|
+
// Add marker cluster object to map
|
56
|
+
map.addLayer(markers);
|
57
|
+
|
58
|
+
// Listeners for marker cluster clicks
|
59
|
+
markers.on('clusterclick', function(e){
|
60
|
+
|
61
|
+
//hide sidebar if it is visible
|
62
|
+
if (sidebar.isVisible()){
|
63
|
+
sidebar.hide();
|
64
|
+
}
|
65
|
+
|
66
|
+
//if map is at the lowest zoom level
|
67
|
+
if (map.getZoom() === Blacklight.mapOptions.maxzoom){
|
68
|
+
|
69
|
+
var placenames = generatePlacenamesObject(e.layer._markers);
|
70
|
+
|
71
|
+
|
72
|
+
offsetMap(e);
|
73
|
+
|
74
|
+
//Update sidebar div with new html
|
75
|
+
$('#blacklight-map-sidebar').html(buildList(placenames));
|
76
|
+
|
77
|
+
//Show the sidebar!
|
78
|
+
sidebar.show();
|
79
|
+
}
|
80
|
+
});
|
81
|
+
|
82
|
+
//Add click listener to map
|
83
|
+
map.on('click', function(e){
|
84
|
+
|
85
|
+
//hide the sidebar if it is visible
|
86
|
+
if (sidebar.isVisible()){
|
87
|
+
sidebar.hide();
|
88
|
+
}
|
89
|
+
});
|
90
|
+
|
91
|
+
//drag listener on map
|
92
|
+
map.on('drag', function(e){
|
93
|
+
|
94
|
+
//hide the sidebar if it is visible
|
95
|
+
if (sidebar.isVisible()){
|
96
|
+
sidebar.hide();
|
97
|
+
}
|
98
|
+
});
|
99
|
+
|
100
|
+
});
|
101
|
+
|
102
|
+
Blacklight.mapOptions = {
|
103
|
+
tileurl : 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
104
|
+
mapattribution : 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'
|
105
|
+
};
|
106
|
+
|
107
|
+
function buildList(placenames){
|
108
|
+
var html = "";
|
109
|
+
$.each(placenames, function(i,val){
|
110
|
+
html += "<h2>" + i + "</h2>";
|
111
|
+
html += "<ul class='sidebar-list'>";
|
112
|
+
$.each(val, function(j, val2){
|
113
|
+
html += val2;
|
114
|
+
});
|
115
|
+
html += "</ul>";
|
116
|
+
});
|
117
|
+
return html;
|
118
|
+
}
|
119
|
+
|
120
|
+
// Generates placenames object
|
121
|
+
function generatePlacenamesObject(markers){
|
122
|
+
var placenames = {};
|
123
|
+
$.each(markers, function(i,val){
|
124
|
+
if (!(val.feature.properties.placename in placenames)){
|
125
|
+
placenames[val.feature.properties.placename] = [];
|
126
|
+
}
|
127
|
+
placenames[val.feature.properties.placename].push(val.feature.properties.html);
|
128
|
+
});
|
129
|
+
return placenames;
|
130
|
+
}
|
131
|
+
|
132
|
+
// Move the map so that it centers the clicked cluster TODO account for various size screens
|
133
|
+
function offsetMap(e){
|
134
|
+
mapWidth = $('#blacklight-map').width();
|
135
|
+
mapHeight = $('#blacklight-map').height();
|
136
|
+
if (!e.latlng.equals(map.getCenter())){
|
137
|
+
map.panBy([(e.originalEvent.layerX - (mapWidth/4)), (e.originalEvent.layerY - (mapHeight/2))]);
|
138
|
+
}else{
|
139
|
+
map.panBy([(mapWidth/4), 0]);
|
140
|
+
}
|
141
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
/*
|
2
|
+
*= require leaflet
|
3
|
+
*= require leaflet.markercluster
|
4
|
+
*= require leaflet.markercluster.default
|
5
|
+
*= require L.Control.Sidebar.css
|
6
|
+
*/
|
7
|
+
|
8
|
+
.view-icon-maps {
|
9
|
+
&:before { content: "\e135"; }
|
10
|
+
}
|
11
|
+
|
12
|
+
#blacklight-map{
|
13
|
+
height: 550px;
|
14
|
+
}
|
15
|
+
|
16
|
+
.sidebar-thumb{
|
17
|
+
height: 64px;
|
18
|
+
width: 64px;
|
19
|
+
}
|
20
|
+
|
21
|
+
.sidebar-list{
|
22
|
+
padding-left: 0;
|
23
|
+
list-style: none;
|
24
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module BlacklightMapsHelper
|
2
|
+
|
3
|
+
def show_map_div
|
4
|
+
data_attributes = {
|
5
|
+
:maxzoom => blacklight_config.view.maps.maxzoom,
|
6
|
+
:tileurl => blacklight_config.view.maps.tileurl
|
7
|
+
|
8
|
+
}
|
9
|
+
|
10
|
+
content_tag(:div, "", id: "blacklight-map",
|
11
|
+
data: data_attributes
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def serialize_geojson
|
16
|
+
geojson_docs = {type: "FeatureCollection", features: []}
|
17
|
+
@response.docs.each_with_index do |doc, counter|
|
18
|
+
if doc[blacklight_config.view.maps.placename_coord_field]
|
19
|
+
doc[blacklight_config.view.maps.placename_coord_field].each do |loc|
|
20
|
+
values = loc.split('|')
|
21
|
+
feature = {type: "Feature", geometry: {type: "Point",
|
22
|
+
coordinates: [values[2].to_f, values[1].to_f]},
|
23
|
+
properties: {placename: values[0],
|
24
|
+
html: render_leaflet_sidebar_partial(doc)}}
|
25
|
+
geojson_docs[:features].push feature
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
return geojson_docs.to_json
|
30
|
+
end
|
31
|
+
|
32
|
+
def render_leaflet_sidebar_partial(doc)
|
33
|
+
render partial: 'catalog/index_maps', locals: {document: SolrDocument.new(doc)}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<% # the way each document will be viewed in the sidebar list -%>
|
2
|
+
<li class='media'>
|
3
|
+
<%= render_thumbnail_tag document, {class: 'sidebar-thumb media-object'}, {class: 'pull-left'} %>
|
4
|
+
<div class='media-body'>
|
5
|
+
<h4 class='media-heading'>
|
6
|
+
<%= link_to_document document, :label=>document_show_link_field(document) %>
|
7
|
+
</h4>
|
8
|
+
</div>
|
9
|
+
</li>
|