blacklight_heatmaps 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +13 -0
  3. data/README.md +56 -0
  4. data/Rakefile +13 -0
  5. data/app/assets/javascripts/blacklight_heatmaps/blacklight_heatmaps.js +10 -0
  6. data/app/assets/javascripts/blacklight_heatmaps/default.js +6 -0
  7. data/app/assets/javascripts/blacklight_heatmaps/viewers/index.js +89 -0
  8. data/app/assets/javascripts/blacklight_heatmaps/viewers/show.js +34 -0
  9. data/app/assets/stylesheets/blacklight_heatmaps/default.scss +14 -0
  10. data/app/controllers/blacklight_heatmaps/application_controller.rb +5 -0
  11. data/app/helpers/blacklight/maps_helper.rb +59 -0
  12. data/app/models/concerns/blacklight_heatmaps/bounding_box.rb +50 -0
  13. data/app/models/concerns/blacklight_heatmaps/exceptions.rb +10 -0
  14. data/app/models/concerns/blacklight_heatmaps/geometry_parser.rb +21 -0
  15. data/app/models/concerns/blacklight_heatmaps/geometry_solr_document.rb +11 -0
  16. data/app/models/concerns/blacklight_heatmaps/point.rb +31 -0
  17. data/app/models/concerns/blacklight_heatmaps/solr_facet_heatmap_behavior.rb +53 -0
  18. data/app/views/catalog/_document_heatmaps.html.erb +5 -0
  19. data/app/views/catalog/_show_leaflet_map_default.html.erb +5 -0
  20. data/app/views/catalog/index.json.jbuilder +10 -0
  21. data/app/views/layouts/blacklight_heatmaps/application.html.erb +14 -0
  22. data/config/routes.rb +2 -0
  23. data/lib/blacklight_heatmaps.rb +7 -0
  24. data/lib/blacklight_heatmaps/engine.rb +8 -0
  25. data/lib/blacklight_heatmaps/version.rb +3 -0
  26. data/lib/generators/blacklight_heatmaps/install_generator.rb +41 -0
  27. data/lib/generators/blacklight_heatmaps/templates/blacklight_heatmaps.js +1 -0
  28. data/lib/generators/blacklight_heatmaps/templates/blacklight_heatmaps.scss +3 -0
  29. data/lib/tasks/blacklight_heatmaps_tasks.rake +25 -0
  30. data/spec/features/index_page_map_spec.rb +15 -0
  31. data/spec/features/show_page_map_spec.rb +15 -0
  32. data/spec/helpers/blacklight/maps_helper_spec.rb +38 -0
  33. data/spec/models/concerns/blacklight_heatmaps/bounding_box_spec.rb +31 -0
  34. data/spec/models/concerns/blacklight_heatmaps/geometry_parser_spec.rb +24 -0
  35. data/spec/models/concerns/blacklight_heatmaps/geometry_solr_document_spec.rb +34 -0
  36. data/spec/models/concerns/blacklight_heatmaps/point_spec.rb +18 -0
  37. data/spec/models/concerns/blacklight_heatmaps/solr_facet_heatmap_behavior_spec.rb +67 -0
  38. data/spec/spec_helper.rb +26 -0
  39. data/spec/test_app_templates/lib/generators/test_app_generator.rb +27 -0
  40. data/spec/views/catalog/_document_heatmaps.html.erb_spec.rb +19 -0
  41. data/spec/views/catalog/_show_leaflet_map_default.html.erb_spec.rb +32 -0
  42. metadata +242 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eb7c89ff10e6644af8ec6c7ac604b50f7b6e9322
4
+ data.tar.gz: a9b83bde4dcce36145deb45db7f3a523ae994010
5
+ SHA512:
6
+ metadata.gz: 63b31f0cb11727db4067c3e0cdb4047b54e0b6126a9f2b32a398f228bfffdc63b0aba90efdb4f4956b57c8df55dd8abd1db912b232b1fbb5119d5566eb63763e
7
+ data.tar.gz: 1b11f4e59a9166fe570f7e93d3f2b1b7c2199b5a95093be250a1d5214506474766e58226937a26b5a324013ea7ee436dee97a171aeb75325fccc724287243596
@@ -0,0 +1,13 @@
1
+ Copyright 2016 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.
@@ -0,0 +1,56 @@
1
+ # BlacklightHeatmaps
2
+ [![Build Status](https://travis-ci.org/sul-dlss/blacklight_heatmaps.svg?branch=master)](https://travis-ci.org/sul-dlss/blacklight_heatmaps) | [![Coverage Status](https://coveralls.io/repos/github/sul-dlss/blacklight_heatmaps/badge.svg?branch=master)](https://coveralls.io/github/sul-dlss/blacklight_heatmaps?branch=master)
3
+
4
+ ![blacklight_heatmap](https://cloud.githubusercontent.com/assets/1656824/16598401/d0538fce-42cb-11e6-86f8-81fd37ab2abe.gif)
5
+
6
+ ## Features
7
+ - Configurable heatmaps of result sets
8
+ - Works with center points and bounding box data
9
+ - Show page map view
10
+ - Changeout the basemap to any tile layer
11
+ - _Really_ fast with large data sets
12
+ - Utilizes Solr's [facet heatmap](https://issues.apache.org/jira/browse/SOLR-7005) feature to provide snappy results. Tested with an index > 10,000,000 records.
13
+ - Customizable result view template
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'blacklight_heatmaps'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```sh
26
+ bundle install
27
+ ```
28
+
29
+ Run the BlacklightMaps installer:
30
+
31
+ ```sh
32
+ rails generate blacklight_heatmaps:install
33
+ ```
34
+
35
+ ## Getting started
36
+
37
+ BlacklightHeatmaps expects your data to be indexed as a [Spatial Recursive Prefix Tree](https://cwiki.apache.org/confluence/display/solr/Spatial+Search#SpatialSearch-RPT) type. The plugin currently supports data indexed in formats:
38
+
39
+ - `x y` Syntax. example: "-121.631609 36.688128"
40
+ - CQL ENVELOPE Syntax (`minX, maxX, maxY, minY`). example: "ENVELOPE(122.934585571, 153.987060547, 45.522888184, 20.422889709)"
41
+
42
+ Additional formats could be added by extending `BlacklightHeatmaps::GeometryParser`
43
+
44
+ ## Development
45
+
46
+ Run Solr and Blacklight (with BlacklightMaps) for interactive development:
47
+
48
+ ```sh
49
+ bundle exec rake blacklight_heatmaps:server
50
+ ```
51
+
52
+ Run the test suite
53
+
54
+ ```sh
55
+ bundle exec rake ci
56
+ ```
@@ -0,0 +1,13 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ Bundler::GemHelper.install_tasks
8
+
9
+ load 'tasks/blacklight_heatmaps.rake'
10
+
11
+ require 'engine_cart/rake_task'
12
+
13
+ task default: :spec
@@ -0,0 +1,10 @@
1
+ !(function (global) {
2
+ 'use strict';
3
+
4
+ var BlacklightHeatmaps = L.Class.extend({
5
+ statics: {
6
+ __version__: '0.1.0',
7
+ },
8
+ });
9
+ global.BlacklightHeatmaps = BlacklightHeatmaps;
10
+ }(this));
@@ -0,0 +1,6 @@
1
+ //= require geostats
2
+ //= require leaflet
3
+ //= require L.Control.Sidebar
4
+ //= require leaflet_solr_heatmap
5
+ //= require blacklight_heatmaps/blacklight_heatmaps
6
+ //= require_tree ./viewers
@@ -0,0 +1,89 @@
1
+ Blacklight.onLoad(function () {
2
+ 'use strict';
3
+
4
+ $('[data-index-map]').each(function () {
5
+ BlacklightHeatmaps.indexView(this, {});
6
+ });
7
+ });
8
+
9
+ !(function (global) {
10
+ 'use strict';
11
+
12
+ var IndexView = L.Class.extend({
13
+ options: {},
14
+
15
+ initialize: function (el, options) {
16
+ var _this = this;
17
+ var $el = $(el);
18
+ var requestUrl = $el.data().searchUrl + '&format=json';
19
+ var geometryField = $el.data().geometryField;
20
+ var template = $el.data().sidebarTemplate;
21
+ var colorRamp = $el.data().colorRamp;
22
+
23
+ var map = L.map($el[0].id).setView([0, 0], 1);
24
+ var basemap = L.tileLayer($el.data().basemap, {
25
+ attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="http://cartodb.com/attributions">CartoDB</a>',
26
+ }).addTo(map);
27
+
28
+ var solrLayer = L.solrHeatmap(requestUrl, {
29
+ field: geometryField,
30
+ maxSampleSize: 50,
31
+ colors: colorRamp,
32
+ }).addTo(map);
33
+
34
+ var sidebar = L.control.sidebar('index-map-sidebar', {
35
+ position: 'right',
36
+ });
37
+
38
+ map.addControl(sidebar);
39
+
40
+ solrLayer.on('click', function (e) {
41
+ if (!sidebar.isVisible()) {
42
+ map.setView(e.latlng);
43
+ } else {
44
+ var point = map.project(e.latlng);
45
+ var offset = sidebar.getOffset();
46
+ var newPoint = L.point(point.x - (offset / 2), point.y);
47
+ map.setView(map.unproject(newPoint));
48
+ }
49
+
50
+ sidebar.show();
51
+ });
52
+
53
+ solrLayer.on('dataAdded', function (e) {
54
+ if (e.response && e.response.docs) {
55
+ var html = '';
56
+ $.each(e.response.docs, function (i, value) {
57
+ html += L.Util.template(template, value);
58
+ });
59
+
60
+ sidebar.setContent(html);
61
+
62
+ var docCount = e.response.pages.total_count;
63
+ $('#sortAndPerPage .page_links').html(
64
+ parseInt(docCount).toLocaleString() + ' ' +
65
+ _this.pluralize(docCount, 'item') + ' found'
66
+ );
67
+ }
68
+ });
69
+
70
+ $(document).on('turbolinks:click', function (e) {
71
+ e.preventDefault();
72
+ });
73
+ },
74
+
75
+ pluralize: function (count, word) {
76
+ switch (count) {
77
+ case 1:
78
+ return word;
79
+ default:
80
+ return word + 's';
81
+ }
82
+ },
83
+ });
84
+
85
+ global.BlacklightHeatmaps.IndexView = IndexView;
86
+ global.BlacklightHeatmaps.indexView = function (el, options) {
87
+ return new IndexView(el, options);
88
+ };
89
+ })(this);
@@ -0,0 +1,34 @@
1
+ Blacklight.onLoad(function () {
2
+ 'use strict';
3
+
4
+ $('[data-show-map]').each(function () {
5
+ BlacklightHeatmaps.showView(this);
6
+ });
7
+ });
8
+
9
+ !(function (global) {
10
+ 'use strict';
11
+
12
+ var ShowView = L.Class.extend({
13
+ options: {},
14
+
15
+ initialize: function (el, options) {
16
+ var $el = $(el);
17
+ var features = $el.data().features;
18
+
19
+ var map = L.map($el[0].id).setView([0, 0], 1);
20
+ var basemap = L.tileLayer($el.data().basemap, {
21
+ attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="http://cartodb.com/attributions">CartoDB</a>',
22
+ }).addTo(map);
23
+
24
+ var features = L.geoJson(features).addTo(map);
25
+
26
+ map.fitBounds(features.getBounds());
27
+ },
28
+ });
29
+
30
+ global.BlacklightHeatmaps.ShowView = ShowView;
31
+ global.BlacklightHeatmaps.showView = function (el, options) {
32
+ return new ShowView(el, options);
33
+ };
34
+ })(this);
@@ -0,0 +1,14 @@
1
+ @import 'leaflet';
2
+ @import 'L.Control.Sidebar';
3
+
4
+ .blacklight-heatmaps-show-map {
5
+ height: 500px;
6
+ }
7
+
8
+ .blacklight-heatmaps-index-map {
9
+ height: 500px;
10
+ }
11
+
12
+ .view-icon-heatmaps {
13
+ &:before { content: "\e135"; }
14
+ }
@@ -0,0 +1,5 @@
1
+ module BlacklightHeatmaps
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,59 @@
1
+ module Blacklight
2
+ module MapsHelper
3
+ ##
4
+ # Creates a div with needed attributes, used to display the index map
5
+ # @return String
6
+ def index_map_div
7
+ content_tag(
8
+ :div,
9
+ nil,
10
+ class: 'blacklight-heatmaps-index-map',
11
+ id: 'index-map',
12
+ data: index_map_data_attributes
13
+ )
14
+ end
15
+
16
+ ##
17
+ # The Leaflet template used for constructing the sidebar documents.
18
+ # Variables from returned docs should be keys within curly braces
19
+ # e.g. {title_display}
20
+ # @return String
21
+ def sidebar_template
22
+ <<-HTMLTEMPLATE
23
+ <div class='media'>
24
+ <div class='media-body'>
25
+ <h3 class='media-heading'>
26
+ <a href=\"#{document_path}\"}>
27
+ {#{blacklight_config.index.title_field}}
28
+ </a>
29
+ </h3>
30
+ </div>
31
+ </div>
32
+ HTMLTEMPLATE
33
+ end
34
+
35
+ private
36
+
37
+ ##
38
+ # Document path used for creating client side links to documents from a
39
+ # template
40
+ # @return String
41
+ def document_path
42
+ "#{search_catalog_path}/{#{blacklight_config.document_unique_id_param}}"
43
+ end
44
+
45
+ ##
46
+ # Data attributes used in displaying the index map
47
+ # @return Hash
48
+ def index_map_data_attributes
49
+ {
50
+ index_map: true,
51
+ basemap: blacklight_config.basemap,
52
+ search_url: request.url,
53
+ geometry_field: blacklight_config.geometry_field,
54
+ sidebar_template: sidebar_template,
55
+ color_ramp: blacklight_config.view.heatmaps.color_ramp
56
+ }
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,50 @@
1
+ module BlacklightHeatmaps
2
+ ##
3
+ # Used for creating and parsing bounding boxes from CQL Envelope syntax
4
+ class BoundingBox
5
+ ##
6
+ # @param [String, Integer, Float] west
7
+ # @param [String, Integer, Float] south
8
+ # @param [String, Integer, Float] east
9
+ # @param [String, Integer, Float] north
10
+ def initialize(west, south, east, north)
11
+ @west = west.to_f
12
+ @south = south.to_f
13
+ @east = east.to_f
14
+ @north = north.to_f
15
+ end
16
+
17
+ ##
18
+ # Returns a bounding box in ENVELOPE syntax
19
+ # @return [String]
20
+ def to_envelope
21
+ "ENVELOPE(#{west}, #{east}, #{north}, #{south})"
22
+ end
23
+
24
+ ##
25
+ # @return String
26
+ def to_geojson
27
+ {
28
+ type: 'Polygon',
29
+ coordinates: [
30
+ [
31
+ [west, south],
32
+ [west, north],
33
+ [east, north],
34
+ [east, south],
35
+ [west, south]
36
+ ]
37
+ ]
38
+ }.to_json
39
+ end
40
+
41
+ def self.from_envelope(envelope)
42
+ envelope = envelope[/.*ENVELOPE\(([^\)]*)/,1].split(',')
43
+ new(envelope[0], envelope[3], envelope[1], envelope[2])
44
+ end
45
+
46
+ private
47
+
48
+ attr_reader :west, :south, :east, :north
49
+ end
50
+ end
@@ -0,0 +1,10 @@
1
+ module BlacklightHeatmaps
2
+ module Exceptions
3
+ class UnknownSpatialDataType < StandardError
4
+ def message
5
+ 'BlacklightHeatmaps does not know how to parse that type of spatial data. '\
6
+ 'Please try using the CQL ENVELOPE or X Y syntax.'
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ module BlacklightHeatmaps
2
+ ##
3
+ # Parser that tries to understand the type of geospatial data stored in a
4
+ # String and sends that to the correct parsing class.
5
+ class GeometryParser
6
+ ##
7
+ # Utility method for determing the type of spatial data stored in a string
8
+ # field
9
+ # @param String
10
+ def self.parse(geometry)
11
+ case geometry
12
+ when /^ENVELOPE\(.*\)$/
13
+ BlacklightHeatmaps::BoundingBox.from_envelope(geometry)
14
+ when /^(\-?\d+(\.\d+)?) \w*(\-?\d+(\.\d+)?)$/
15
+ BlacklightHeatmaps::Point.from_lng_lat(geometry)
16
+ else
17
+ raise BlacklightHeatmaps::Exceptions::UnknownSpatialDataType
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module BlacklightHeatmaps
2
+ ##
3
+ # Provides methods to convert Solr geometry strings
4
+ module GeometrySolrDocument
5
+ def to_geojson(blacklight_config = nil)
6
+ return unless blacklight_config.try(:geometry_field) && fetch(blacklight_config.geometry_field, nil)
7
+ BlacklightHeatmaps::GeometryParser
8
+ .parse(fetch(blacklight_config.geometry_field)).to_geojson
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ module BlacklightHeatmaps
2
+ ##
3
+ # A geometry class to characterize points. Can be longitude and latitude.
4
+ class Point
5
+ def initialize(x, y)
6
+ @x = x.to_f
7
+ @y = y.to_f
8
+ end
9
+
10
+ ##
11
+ # @return String
12
+ def to_geojson
13
+ {
14
+ type: 'Point',
15
+ coordinates: [
16
+ x, y
17
+ ]
18
+ }.to_json
19
+ end
20
+
21
+ ##
22
+ # @param String
23
+ def self.from_lng_lat(lng_lat)
24
+ new(*lng_lat.split(' '))
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :x, :y
30
+ end
31
+ end
@@ -0,0 +1,53 @@
1
+ module BlacklightHeatmaps
2
+ ##
3
+ # Extends itself into a consuming application's SearchBuilder and adds
4
+ # relevancy, spatial search, and heatmap functionality.
5
+ module SolrFacetHeatmapBehavior
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ self.default_processor_chain += [:add_solr_facet_heatmap]
10
+ end
11
+
12
+ ##
13
+ # Add Solr spatial heatmap parameters to Solr request
14
+ def add_solr_facet_heatmap(solr_parameters = {})
15
+ if blacklight_params[:bbox]
16
+ solr_parameters['facet.heatmap'] = geometry_field
17
+ solr_parameters['facet.heatmap.geom'] = bbox_as_range
18
+ solr_parameters[:bq] ||= []
19
+ solr_parameters[:bq] << "#{geometry_field}:\"IsWithin(#{bbox_as_envelope})\""
20
+ solr_parameters[:fq] ||= []
21
+ solr_parameters[:fq] << "#{geometry_field}:\"Intersects(#{bbox_as_envelope})\""
22
+ end
23
+ solr_parameters
24
+ end
25
+
26
+ def geometry_field
27
+ blacklight_config.geometry_field
28
+ end
29
+
30
+ ##
31
+ # `bbox` parameter is in format "west,south,east,north"
32
+ # @return Array
33
+ def bbox
34
+ blacklight_params[:bbox].split(',')
35
+ end
36
+
37
+ ##
38
+ # Returned in CQL Envelope syntax
39
+ # https://cwiki.apache.org/confluence/display/solr/Spatial+Search
40
+ # @return String
41
+ def bbox_as_envelope
42
+ BlacklightHeatmaps::BoundingBox.new(*bbox).to_envelope
43
+ end
44
+
45
+ ##
46
+ # Returned in rectangle-range syntax ["-180 -90" TO "180 90"]
47
+ # https://cwiki.apache.org/confluence/display/solr/Spatial+Search
48
+ # @return String
49
+ def bbox_as_range
50
+ "[\"#{bbox[0]} #{bbox[1]}\" TO \"#{bbox[2]} #{bbox[3]}\"]"
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,5 @@
1
+ <div class='blacklight-heatmaps-index-map-container'>
2
+ <%= index_map_div %>
3
+ <%= content_tag(:div, id: 'index-map-sidebar') do %>
4
+ <% end %>
5
+ </div>
@@ -0,0 +1,5 @@
1
+ <% features = document.to_geojson(blacklight_config) %>
2
+
3
+ <% unless features.nil? %>
4
+ <%= content_tag(:div, nil, class: 'blacklight-heatmaps-show-map', id: "map-#{document.id}", data: {show_map: true, features: features, basemap: blacklight_config.basemap}) %>
5
+ <% end %>
@@ -0,0 +1,10 @@
1
+ ##
2
+ # Overrides default index.json.jbuilder from Blacklight by adding the
3
+ # `facet_heatmaps` key/value
4
+
5
+ json.response do
6
+ json.docs @presenter.documents
7
+ json.facets @presenter.search_facets_as_json
8
+ json.facet_heatmaps @response['facet_counts']['facet_heatmaps']
9
+ json.pages @presenter.pagination_info
10
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>BlacklightHeatmaps</title>
5
+ <%= stylesheet_link_tag "blacklight_heatmaps/application", media: "all" %>
6
+ <%= javascript_include_tag "blacklight_heatmaps/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,2 @@
1
+ BlacklightHeatmaps::Engine.routes.draw do
2
+ end
@@ -0,0 +1,7 @@
1
+ require 'leaflet-rails'
2
+ require 'leaflet-sidebar-rails'
3
+ require 'blacklight'
4
+
5
+ module BlacklightHeatmaps
6
+ require 'blacklight_heatmaps/engine'
7
+ end
@@ -0,0 +1,8 @@
1
+ module BlacklightHeatmaps
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace BlacklightHeatmaps
4
+ initializer 'blacklight-maps.helpers' do |app|
5
+ ActionView::Base.send :include, Blacklight::MapsHelper
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module BlacklightHeatmaps
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,41 @@
1
+ require 'rails/generators'
2
+
3
+ module BlacklightHeatmaps
4
+ class Install < Rails::Generators::Base
5
+ def add_gems
6
+ gem 'blacklight_heatmaps'
7
+ end
8
+
9
+ source_root File.expand_path('../templates', __FILE__)
10
+
11
+ def assets
12
+ copy_file 'blacklight_heatmaps.scss', 'app/assets/stylesheets/blacklight_heatmaps.scss'
13
+ copy_file 'blacklight_heatmaps.js', 'app/assets/javascripts/blacklight_heatmaps.js'
14
+ end
15
+
16
+ def configuration
17
+ inject_into_file 'app/controllers/catalog_controller.rb', after: 'configure_blacklight do |config|' do
18
+ "\n # BlacklightHeatmaps configuration values" \
19
+ "\n config.geometry_field = :geo_srpt" \
20
+ "\n config.basemap = 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png'" \
21
+ "\n config.show.partials.insert(1, :show_leaflet_map)" \
22
+ "\n config.view.heatmaps.partials = []" \
23
+ "\n #Heatmap color ramp. For best results, use http://colorbrewer2.org or http://tristen.ca/hcl-picker/#/hlc/5/1" \
24
+ "\n config.view.heatmaps.color_ramp = ['#ffffcc', '#a1dab4', '#41b6c4', '#2c7fb8', '#253494']" \
25
+ "\n"
26
+ end
27
+ end
28
+
29
+ def add_model_mixin
30
+ inject_into_file 'app/models/solr_document.rb', after: 'include Blacklight::Solr::Document' do
31
+ "\n include BlacklightHeatmaps::GeometrySolrDocument\n"
32
+ end
33
+ end
34
+
35
+ def inject_search_builder
36
+ inject_into_file 'app/models/search_builder.rb', after: /include Blacklight::Solr::SearchBuilderBehavior.*$/ do
37
+ "\n include BlacklightHeatmaps::SolrFacetHeatmapBehavior\n"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1 @@
1
+ //= require blacklight_heatmaps/default
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= require blacklight_heatmaps/default
3
+ */
@@ -0,0 +1,25 @@
1
+ # Tasks shared with the consuming application
2
+ namespace :blacklight_heatmaps do
3
+ namespace :index do
4
+ desc 'Put sample data into Solr'
5
+ task :seed, [:datafile] => [:environment] do |_t, args|
6
+ args.with_defaults(datafile: 'sample_solr_documents')
7
+ fn = File.join(BlacklightHeatmaps::Engine.root, 'solr', args[:datafile] + '.yml')
8
+ puts "Indexing sample data from #{fn}"
9
+ docs = YAML.load(File.open(fn))
10
+ conn = Blacklight.default_index.connection
11
+ conn.add docs
12
+ conn.commit
13
+ end
14
+
15
+ desc 'Fetch random data from WhosOnFirst gazetteer and index into Solr'
16
+ task :seed_random, [:n] => [:environment] do |_t, args|
17
+ args.with_defaults(n: 10)
18
+ puts "Indexing #{args[:n]} random data records"
19
+ docs = YAML.load(`bundle exec ruby #{File.join(BlacklightHeatmaps::Engine.root, 'scripts', 'sample_whosonfirst.rb')} #{args[:n]}`)
20
+ conn = Blacklight.default_index.connection
21
+ conn.add docs
22
+ conn.commit
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'Index page map', js: true do
4
+ it 'renders a leaflet map' do
5
+ visit search_catalog_path(q: 'strong', view: 'heatmaps')
6
+ expect(page).to have_css '.leaflet-map-pane'
7
+ # Zoomed to world
8
+ expect(page).to have_css 'img[src="http://a.basemaps.cartocdn.com/light_all/1/0/0.png"]'
9
+ expect(page).to have_css '#index-map-sidebar', visible: false
10
+ page.find('svg g path').click
11
+ expect(page).to have_css '#index-map-sidebar', visible: true
12
+ expect(page)
13
+ .to have_css 'h3.media-heading a', text: '"Strong Medicine speaks"'
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'Show map map', js: true do
4
+ it 'renders a leaflet map' do
5
+ visit solr_document_path '43037890'
6
+ expect(page).to have_css '.leaflet-map-pane'
7
+ # Zoomed to Kazakhstan
8
+ expect(page).to have_css 'img[src="http://b.basemaps.cartocdn.com/light_all/4/11/5.png"]'
9
+ expect(page).to have_css 'svg g path'
10
+ end
11
+ it 'renders a point type' do
12
+ visit solr_document_path '34860108'
13
+ expect(page).to have_css '.leaflet-marker-icon'
14
+ end
15
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Blacklight::MapsHelper do
4
+ let(:blacklight_config) do
5
+ Blacklight::Configuration.new(
6
+ basemap: 'http://www.example.com/{z}/{x}/{y}.png',
7
+ geometry_field: 'geo_srpt',
8
+ index: Blacklight::OpenStructWithHashAccess.new(
9
+ title_field: 'title_display'
10
+ )
11
+ )
12
+ end
13
+ before do
14
+ allow(helper).to receive_messages(blacklight_config: blacklight_config)
15
+ end
16
+ describe '#index_map_div' do
17
+ it 'renders html with the required elements/attributes' do
18
+ expect(helper.index_map_div)
19
+ .to have_css '#index-map.blacklight-heatmaps-index-map'
20
+ expect(helper.index_map_div)
21
+ .to have_css '[data-index-map="true"]'
22
+ expect(helper.index_map_div)
23
+ .to have_css '[data-search-url="http://test.host"]'
24
+ expect(helper.index_map_div)
25
+ .to have_css '[data-geometry-field="geo_srpt"]'
26
+ expect(helper.index_map_div)
27
+ .to have_css '[data-basemap="http://www.example.com/{z}/{x}/{y}.png"]'
28
+ expect(helper.index_map_div).to have_css '[data-sidebar-template]'
29
+ expect(helper.index_map_div).to have_css '[data-color-ramp]'
30
+ end
31
+ end
32
+ describe '#sidebar_template' do
33
+ it 'renders html template used in sidebar' do
34
+ expect(helper.sidebar_template)
35
+ .to have_css '.media .media-body h3.media-heading a', text: '{title_display}'
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe BlacklightHeatmaps::BoundingBox do
4
+ describe '#initialize' do
5
+ it 'handles multiple input types as arguments' do
6
+ expect(described_class.new('1', '1', '1', '1')).to be_an described_class
7
+ expect(described_class.new(1, 2, 3, 3)).to be_an described_class
8
+ expect(described_class.new(1.1, 2.1, 3.1, 3.1)).to be_an described_class
9
+ end
10
+ end
11
+ describe '#to_envelope' do
12
+ let(:example_box) { described_class.new(-160, -80, 120, 70) }
13
+ it 'creates an envelope syntax version of the bounding box' do
14
+ expect(example_box.to_envelope).to eq 'ENVELOPE(-160.0, 120.0, 70.0, -80.0)'
15
+ end
16
+ end
17
+ describe '#to_geojson' do
18
+ let(:example_box) { described_class.new(-160, -80, 120, 70) }
19
+ it 'creates a geoJSON string' do
20
+ expect(example_box.to_geojson).to eq '{"type":"Polygon","coordinates":[[[-160.0,-80.0],[-160.0,70.0],[120.0,70.0],[120.0,-80.0],[-160.0,-80.0]]]}'
21
+ end
22
+ end
23
+ describe '#from_rectangle' do
24
+ let(:envelope) { 'ENVELOPE(-160.0, 120.0, 70.0, -80.0)' }
25
+ let(:example_box) { described_class.from_envelope(envelope) }
26
+ it 'parses and creates a Geoblacklight::BoundingBox from a Solr lat-lon' do
27
+ expect(example_box).to be_an described_class
28
+ expect(example_box.to_envelope).to eq envelope
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe BlacklightHeatmaps::GeometryParser do
4
+ describe '.parse' do
5
+ context 'when parsing a CQL ENVELOPE' do
6
+ it 'returns a BlacklightHeatmaps::BoundingBox' do
7
+ expect(described_class.parse('ENVELOPE(1,2,4,3)'))
8
+ .to be_an BlacklightHeatmaps::BoundingBox
9
+ end
10
+ end
11
+ context 'when parsing an X Y coordinate' do
12
+ it 'returns a BlacklightHeatmaps::Point' do
13
+ expect(described_class.parse('-180 90')).to be_an BlacklightHeatmaps::Point
14
+ end
15
+ end
16
+ context 'when parsing an unknown type' do
17
+ it 'raises an exception' do
18
+ expect do
19
+ described_class.parse('123,23 32,123')
20
+ end.to raise_error(BlacklightHeatmaps::Exceptions::UnknownSpatialDataType)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe BlacklightHeatmaps::GeometrySolrDocument do
4
+ subject { SolrDocument.new(fields).to_geojson(blacklight_config) }
5
+
6
+ context 'when configured' do
7
+ let(:fields) { { some_field: 'ENVELOPE(1,2,4,3)' } }
8
+ let(:blacklight_config) { double('BlacklightConfig', geometry_field: :some_field) }
9
+ it 'returns the data from the document as geoJSON' do
10
+ expect(subject).to eq '{"type":"Polygon","coordinates":[[[1.0,3.0],[1.0,4.0],[2.0,4.0],[2.0,3.0],[1.0,3.0]]]}'
11
+ end
12
+ end
13
+ context 'when not configured' do
14
+ let(:fields) { { some_field: 'ENVELOPE(1,2,4,3)' } }
15
+ let(:blacklight_config) { double('BlacklightConfig') }
16
+ it 'returns nil' do
17
+ expect(subject).to be_nil
18
+ end
19
+ end
20
+ context 'when the document has the field' do
21
+ let(:fields) { { some_field: 'ENVELOPE(1,2,4,3)' } }
22
+ let(:blacklight_config) { double('BlacklightConfig', geometry_field: :some_field) }
23
+ it 'returns the data from the document as geoJSON' do
24
+ expect(subject).to eq '{"type":"Polygon","coordinates":[[[1.0,3.0],[1.0,4.0],[2.0,4.0],[2.0,3.0],[1.0,3.0]]]}'
25
+ end
26
+ end
27
+ context 'when the document does not have the field' do
28
+ let(:fields) { { some_other_field: 'ENVELOPE(1,2,4,3)' } }
29
+ let(:blacklight_config) { double('BlacklightConfig', geometry_field: :some_field) }
30
+ it 'returns nil' do
31
+ expect(subject).to be_nil
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe BlacklightHeatmaps::Point do
4
+ describe '#to_geojson' do
5
+ it 'creates geojson from the point' do
6
+ expect(described_class.new(-180, 90).to_geojson)
7
+ .to eq '{"type":"Point","coordinates":[-180.0,90.0]}'
8
+ end
9
+ end
10
+ describe '.from_lng_lat' do
11
+ subject { described_class.from_lng_lat('-180 90') }
12
+ it 'instantiates an instance from a lng lat string' do
13
+ expect(subject).to be_an described_class
14
+ expect(subject.to_geojson)
15
+ .to eq '{"type":"Point","coordinates":[-180.0,90.0]}'
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe BlacklightHeatmaps::SolrFacetHeatmapBehavior do
4
+ let(:blacklight_config) { CatalogController.blacklight_config.deep_copy }
5
+ let(:context) { CatalogController.new }
6
+
7
+ before do
8
+ allow(context).to receive(:blacklight_config).and_return(blacklight_config)
9
+ end
10
+
11
+ let(:search_builder_class) do
12
+ Class.new(Blacklight::SearchBuilder) do
13
+ include Blacklight::Solr::SearchBuilderBehavior
14
+ include BlacklightHeatmaps::SolrFacetHeatmapBehavior
15
+ end
16
+ end
17
+
18
+ let(:search_builder) { search_builder_class.new(context) }
19
+
20
+ describe '#add_solr_facet_heatmap' do
21
+ let(:solr_params) { { fq: [filter: 'stuff'], bq: [boost: 'stuff'] } }
22
+ context 'when bbox is not present' do
23
+ subject { search_builder }
24
+ it 'does not modify the solr parameters' do
25
+ expect(subject.add_solr_facet_heatmap(solr_params)).to eq solr_params
26
+ end
27
+ end
28
+ context 'when a bbox is present' do
29
+ subject { search_builder.with(bbox: '1,2,4,3') }
30
+ it 'leaves solr params in place and adds new params' do
31
+ expect(subject.add_solr_facet_heatmap(solr_params)['facet.heatmap'])
32
+ .to eq :geo_srpt
33
+ expect(subject.add_solr_facet_heatmap(solr_params)['facet.heatmap.geom'])
34
+ .to eq '["1 2" TO "4 3"]'
35
+ expect(subject.add_solr_facet_heatmap(solr_params)[:bq])
36
+ .to include(boost: 'stuff')
37
+ expect(subject.add_solr_facet_heatmap(solr_params)[:bq])
38
+ .to include('geo_srpt:"IsWithin(ENVELOPE(1.0, 4.0, 3.0, 2.0))"')
39
+ expect(subject.add_solr_facet_heatmap(solr_params)[:fq])
40
+ .to include(filter: 'stuff')
41
+ expect(subject.add_solr_facet_heatmap(solr_params)[:fq])
42
+ .to include('geo_srpt:"Intersects(ENVELOPE(1.0, 4.0, 3.0, 2.0))"')
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#bbox' do
48
+ subject { search_builder.with(bbox: '1,2,4,3') }
49
+ it 'returns the bbox parameter split on ,' do
50
+ expect(subject.bbox).to match_array %w(1 2 4 3)
51
+ end
52
+ end
53
+
54
+ describe '#bbox_as_envelope' do
55
+ subject { search_builder.with(bbox: '1,2,4,3') }
56
+ it 'returns the bbox parameter in envelope syntax' do
57
+ expect(subject.bbox_as_envelope).to eq 'ENVELOPE(1.0, 4.0, 3.0, 2.0)'
58
+ end
59
+ end
60
+
61
+ describe '#bbox_as_range' do
62
+ subject { search_builder.with(bbox: '1,2,4,3') }
63
+ it 'returns the bbox parameter in rectangle-range syntax' do
64
+ expect(subject.bbox_as_range).to eq '["1 2" TO "4 3"]'
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,26 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+
3
+ if ENV['COVERAGE'] || ENV['CI']
4
+ require 'simplecov'
5
+ require 'coveralls'
6
+
7
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
8
+ SimpleCov.start do
9
+ add_filter '/spec/'
10
+ end
11
+ end
12
+
13
+ require 'engine_cart'
14
+ EngineCart.load_application!
15
+
16
+ require 'rspec/rails'
17
+
18
+ require 'capybara/poltergeist'
19
+ Capybara.javascript_driver = :poltergeist
20
+
21
+ require 'blacklight'
22
+ require 'blacklight_heatmaps'
23
+
24
+ RSpec.configure do |c|
25
+ c.infer_spec_type_from_file_location!
26
+ end
@@ -0,0 +1,27 @@
1
+ require 'rails/generators'
2
+
3
+ class TestAppGenerator < Rails::Generators::Base
4
+ source_root './spec/test_app_templates'
5
+
6
+ def add_gems
7
+ gem 'blacklight', '~> 6.0'
8
+
9
+ Bundler.with_clean_env do
10
+ run 'bundle install'
11
+ end
12
+ end
13
+
14
+ def run_blacklight_generator
15
+ say_status('warning', 'GENERATING BL', :yellow)
16
+
17
+ generate 'blacklight:install', '--devise'
18
+ end
19
+
20
+ # if you need to generate any additional configuration
21
+ # into the test app, this generator will be run immediately
22
+ # after setting up the application
23
+
24
+ def install_engine
25
+ generate 'blacklight_heatmaps:install'
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'catalog/_document_heatmaps.html.erb' do
4
+ let(:blacklight_config) { Blacklight::Configuration.new }
5
+ before do
6
+ allow(view).to receive(:index_map_div)
7
+ .and_return '<div id="index-map"></div>'.html_safe
8
+ end
9
+ it 'renders a div with needed elements' do
10
+ blacklight_config.configure do |config|
11
+ config.geometry_field = :geo_srpt
12
+ end
13
+ render partial: 'catalog/document_heatmaps',
14
+ locals: { blacklight_config: blacklight_config }
15
+ expect(rendered).to have_css '.blacklight-heatmaps-index-map-container'
16
+ expect(rendered).to have_css '#index-map'
17
+ expect(rendered).to have_css '#index-map-sidebar'
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'catalog/_show_leaflet_map_default.html.erb' do
4
+ let(:document) do
5
+ SolrDocument.new(geo_srpt: 'ENVELOPE(1,2,4,3)', id: 'abc123')
6
+ end
7
+ let(:blacklight_config) { Blacklight::Configuration.new }
8
+ before do
9
+ allow(view).to receive(:document).and_return(document)
10
+ end
11
+ context 'when geojson is available' do
12
+ it 'should render the leaflet container' do
13
+ blacklight_config.configure do |config|
14
+ config.geometry_field = :geo_srpt
15
+ end
16
+ render partial: 'catalog/show_leaflet_map_default',
17
+ locals: { document: document, blacklight_config: blacklight_config }
18
+ expect(rendered).to have_css '.blacklight-heatmaps-show-map'
19
+ expect(rendered).to have_css '#map-abc123'
20
+ expect(rendered).to have_css '[data-basemap]'
21
+ expect(rendered).to have_css '[data-show-map]'
22
+ expect(rendered).to have_css '[data-features]'
23
+ end
24
+ end
25
+ context 'when geojson is not available' do
26
+ it 'renders nothing' do
27
+ render partial: 'catalog/show_leaflet_map_default',
28
+ locals: { document: document, blacklight_config: blacklight_config }
29
+ expect(rendered).to eq "\n"
30
+ end
31
+ end
32
+ end
metadata ADDED
@@ -0,0 +1,242 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blacklight_heatmaps
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jack Reed
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.2.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.2.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: blacklight
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '6.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '6.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: leaflet-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: leaflet-sidebar-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.9
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.9
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '3.4'
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '4'
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '3.4'
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: '4'
103
+ - !ruby/object:Gem::Dependency
104
+ name: engine_cart
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.8'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '0.8'
117
+ - !ruby/object:Gem::Dependency
118
+ name: solr_wrapper
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: capybara
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: poltergeist
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ description: Search and view Blacklight resources on a map.
160
+ email:
161
+ - phillipjreed@gmail.com
162
+ executables: []
163
+ extensions: []
164
+ extra_rdoc_files: []
165
+ files:
166
+ - LICENSE.txt
167
+ - README.md
168
+ - Rakefile
169
+ - app/assets/javascripts/blacklight_heatmaps/blacklight_heatmaps.js
170
+ - app/assets/javascripts/blacklight_heatmaps/default.js
171
+ - app/assets/javascripts/blacklight_heatmaps/viewers/index.js
172
+ - app/assets/javascripts/blacklight_heatmaps/viewers/show.js
173
+ - app/assets/stylesheets/blacklight_heatmaps/default.scss
174
+ - app/controllers/blacklight_heatmaps/application_controller.rb
175
+ - app/helpers/blacklight/maps_helper.rb
176
+ - app/models/concerns/blacklight_heatmaps/bounding_box.rb
177
+ - app/models/concerns/blacklight_heatmaps/exceptions.rb
178
+ - app/models/concerns/blacklight_heatmaps/geometry_parser.rb
179
+ - app/models/concerns/blacklight_heatmaps/geometry_solr_document.rb
180
+ - app/models/concerns/blacklight_heatmaps/point.rb
181
+ - app/models/concerns/blacklight_heatmaps/solr_facet_heatmap_behavior.rb
182
+ - app/views/catalog/_document_heatmaps.html.erb
183
+ - app/views/catalog/_show_leaflet_map_default.html.erb
184
+ - app/views/catalog/index.json.jbuilder
185
+ - app/views/layouts/blacklight_heatmaps/application.html.erb
186
+ - config/routes.rb
187
+ - lib/blacklight_heatmaps.rb
188
+ - lib/blacklight_heatmaps/engine.rb
189
+ - lib/blacklight_heatmaps/version.rb
190
+ - lib/generators/blacklight_heatmaps/install_generator.rb
191
+ - lib/generators/blacklight_heatmaps/templates/blacklight_heatmaps.js
192
+ - lib/generators/blacklight_heatmaps/templates/blacklight_heatmaps.scss
193
+ - lib/tasks/blacklight_heatmaps_tasks.rake
194
+ - spec/features/index_page_map_spec.rb
195
+ - spec/features/show_page_map_spec.rb
196
+ - spec/helpers/blacklight/maps_helper_spec.rb
197
+ - spec/models/concerns/blacklight_heatmaps/bounding_box_spec.rb
198
+ - spec/models/concerns/blacklight_heatmaps/geometry_parser_spec.rb
199
+ - spec/models/concerns/blacklight_heatmaps/geometry_solr_document_spec.rb
200
+ - spec/models/concerns/blacklight_heatmaps/point_spec.rb
201
+ - spec/models/concerns/blacklight_heatmaps/solr_facet_heatmap_behavior_spec.rb
202
+ - spec/spec_helper.rb
203
+ - spec/test_app_templates/lib/generators/test_app_generator.rb
204
+ - spec/views/catalog/_document_heatmaps.html.erb_spec.rb
205
+ - spec/views/catalog/_show_leaflet_map_default.html.erb_spec.rb
206
+ homepage: https://github.com/sul-dlss/blacklight_heatmaps
207
+ licenses:
208
+ - Apache
209
+ metadata: {}
210
+ post_install_message:
211
+ rdoc_options: []
212
+ require_paths:
213
+ - lib
214
+ required_ruby_version: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - ">="
217
+ - !ruby/object:Gem::Version
218
+ version: '0'
219
+ required_rubygems_version: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - ">="
222
+ - !ruby/object:Gem::Version
223
+ version: '0'
224
+ requirements: []
225
+ rubyforge_project:
226
+ rubygems_version: 2.4.5.1
227
+ signing_key:
228
+ specification_version: 4
229
+ summary: Search and view Blacklight resources on a map.
230
+ test_files:
231
+ - spec/features/index_page_map_spec.rb
232
+ - spec/features/show_page_map_spec.rb
233
+ - spec/helpers/blacklight/maps_helper_spec.rb
234
+ - spec/models/concerns/blacklight_heatmaps/bounding_box_spec.rb
235
+ - spec/models/concerns/blacklight_heatmaps/geometry_parser_spec.rb
236
+ - spec/models/concerns/blacklight_heatmaps/geometry_solr_document_spec.rb
237
+ - spec/models/concerns/blacklight_heatmaps/point_spec.rb
238
+ - spec/models/concerns/blacklight_heatmaps/solr_facet_heatmap_behavior_spec.rb
239
+ - spec/spec_helper.rb
240
+ - spec/test_app_templates/lib/generators/test_app_generator.rb
241
+ - spec/views/catalog/_document_heatmaps.html.erb_spec.rb
242
+ - spec/views/catalog/_show_leaflet_map_default.html.erb_spec.rb