foliage 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +9 -0
  4. data/app/assets/images/.keep +0 -0
  5. data/app/assets/images/map/marker/icon-2x.png +0 -0
  6. data/app/assets/images/map/marker/icon.png +0 -0
  7. data/app/assets/images/map/marker/icon.svg +67 -0
  8. data/app/assets/images/map/marker/shadow.png +0 -0
  9. data/app/assets/javascripts/core_ext.js.coffee +61 -0
  10. data/app/assets/javascripts/foliage.js.coffee +23 -0
  11. data/app/assets/javascripts/foliage/band.js.coffee +99 -0
  12. data/app/assets/javascripts/foliage/bubbles.js.coffee +77 -0
  13. data/app/assets/javascripts/foliage/categories.js.coffee +70 -0
  14. data/app/assets/javascripts/foliage/choropleth.js.coffee +51 -0
  15. data/app/assets/javascripts/foliage/color.js.coffee +39 -0
  16. data/app/assets/javascripts/foliage/gradient.js.coffee +72 -0
  17. data/app/assets/javascripts/foliage/heatmap.js.coffee +49 -0
  18. data/app/assets/javascripts/foliage/leaf.js.coffee +422 -0
  19. data/app/assets/javascripts/foliage/path.js.coffee +76 -0
  20. data/app/assets/javascripts/foliage/paths.js.coffee +131 -0
  21. data/app/assets/javascripts/foliage/point_group.js.coffee +83 -0
  22. data/app/assets/javascripts/foliage/points.js.coffee +79 -0
  23. data/app/assets/javascripts/foliage/simple.js.coffee +35 -0
  24. data/app/assets/javascripts/leaflet/geographic_util.js.coffee +23 -0
  25. data/app/assets/javascripts/leaflet/ghost_label.js.coffee +100 -0
  26. data/app/assets/javascripts/leaflet/ghost_label_cluster.js.coffee +192 -0
  27. data/app/assets/javascripts/leaflet/layers_scheduler.js.coffee +57 -0
  28. data/app/assets/javascripts/leaflet/reactive_measure.js.coffee +414 -0
  29. data/app/assets/stylesheets/all.scss +16 -0
  30. data/app/assets/stylesheets/application.css +15 -0
  31. data/app/assets/stylesheets/compass/reset.scss +3 -0
  32. data/app/assets/stylesheets/compass/reset/utilities.scss +142 -0
  33. data/app/assets/stylesheets/leaflet.scss +1093 -0
  34. data/app/assets/stylesheets/leaflet/label.scss +40 -0
  35. data/app/assets/stylesheets/leaflet/tooltip.scss +42 -0
  36. data/app/assets/stylesheets/mixins.scss +131 -0
  37. data/app/assets/stylesheets/reset.scss +89 -0
  38. data/app/assets/stylesheets/variables.scss +47 -0
  39. data/app/helpers/foliage_helper.rb +23 -0
  40. data/lib/foliage.rb +9 -0
  41. data/lib/foliage/leaf.rb +235 -0
  42. data/lib/foliage/rails.rb +2 -0
  43. data/lib/foliage/rails/engine.rb +7 -0
  44. data/lib/foliage/rails/integration.rb +8 -0
  45. data/lib/foliage/version.rb +3 -0
  46. data/vendor/assets/javascripts/.keep +0 -0
  47. data/vendor/assets/javascripts/autosize.js +211 -0
  48. data/vendor/assets/javascripts/geographiclib.js +3074 -0
  49. data/vendor/assets/javascripts/leaflet.js.erb +9175 -0
  50. data/vendor/assets/javascripts/leaflet/draw.js +3573 -0
  51. data/vendor/assets/javascripts/leaflet/easy-button.js +366 -0
  52. data/vendor/assets/javascripts/leaflet/fullscreen.js +162 -0
  53. data/vendor/assets/javascripts/leaflet/heatmap.js +142 -0
  54. data/vendor/assets/javascripts/leaflet/label.js +545 -0
  55. data/vendor/assets/javascripts/leaflet/measure.js +6966 -0
  56. data/vendor/assets/javascripts/leaflet/modal.js +364 -0
  57. data/vendor/assets/javascripts/leaflet/providers.js +479 -0
  58. data/vendor/assets/javascripts/rbush.js +621 -0
  59. data/vendor/assets/stylesheets/.keep +0 -0
  60. data/vendor/assets/stylesheets/bootstrap/mixins.scss +55 -0
  61. data/vendor/assets/stylesheets/bootstrap/variables.scss +10 -0
  62. data/vendor/assets/stylesheets/leaflet.scss +479 -0
  63. data/vendor/assets/stylesheets/leaflet/draw.scss +282 -0
  64. data/vendor/assets/stylesheets/leaflet/easy-button.scss +56 -0
  65. data/vendor/assets/stylesheets/leaflet/fullscreen.scss +2 -0
  66. data/vendor/assets/stylesheets/leaflet/measure.scss +168 -0
  67. data/vendor/assets/stylesheets/leaflet/modal.scss +85 -0
  68. metadata +171 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ddfe5960094bf8bbd1f7250eea1b7470eb04dfe3
4
+ data.tar.gz: 233456b00d6ea184176015a33e739039a5358a68
5
+ SHA512:
6
+ metadata.gz: 29489a93eb3b3fba23d0769c825579911dbefe1317d3061a856ad484636179cf42a96789579e26c5eee90b5db280bec21734a330b118a45b097b823ac15daa0b
7
+ data.tar.gz: 221131a3db6c00fdd8d2331d50574f5aa5ce60746f037bf165e13c92074a832e65e0b1f0764ac2bec74049d374e47f95a7621ce4cf0188283913334b48a5d34e
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014-2016 Ekylibre, Jérémie Bonal
2
+
3
+ The MIT LICENSE
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # Foliage
2
+
3
+ Extracted from [Ekylibre's repo](http://github.com/ekylibre/ekylibre) as part of the [Osmosis](http://github.com/Aquaj/osmosis) fork, this gem provides convenient helpers, javascript and styles to quickly and easily display maps.
4
+
5
+ Based on [Leaflet.js](http://leafletjs.com).
6
+
7
+ ## Dependencies
8
+
9
+ `// TODO`
File without changes
@@ -0,0 +1,67 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6
+ xmlns:cc="http://creativecommons.org/ns#"
7
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8
+ xmlns:svg="http://www.w3.org/2000/svg"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12
+ id="svg2"
13
+ version="1.1"
14
+ inkscape:version="0.91 r13725"
15
+ width="25"
16
+ height="41"
17
+ viewBox="0 0 25 41"
18
+ sodipodi:docname="icon.svg">
19
+ <metadata
20
+ id="metadata8">
21
+ <rdf:RDF>
22
+ <cc:Work
23
+ rdf:about="">
24
+ <dc:format>image/svg+xml</dc:format>
25
+ <dc:type
26
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
27
+ <dc:title></dc:title>
28
+ </cc:Work>
29
+ </rdf:RDF>
30
+ </metadata>
31
+ <defs
32
+ id="defs6" />
33
+ <sodipodi:namedview
34
+ pagecolor="#ffffff"
35
+ bordercolor="#666666"
36
+ borderopacity="1"
37
+ objecttolerance="10"
38
+ gridtolerance="10"
39
+ guidetolerance="10"
40
+ inkscape:pageopacity="0"
41
+ inkscape:pageshadow="2"
42
+ inkscape:window-width="1920"
43
+ inkscape:window-height="1057"
44
+ id="namedview4"
45
+ showgrid="false"
46
+ borderlayer="true"
47
+ inkscape:showpageshadow="false"
48
+ inkscape:zoom="5.7560976"
49
+ inkscape:cx="-82.783211"
50
+ inkscape:cy="-19.01566"
51
+ inkscape:window-x="0"
52
+ inkscape:window-y="0"
53
+ inkscape:window-maximized="1"
54
+ inkscape:current-layer="svg2" />
55
+ <path
56
+ style="fill:#187fce;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.75420874"
57
+ d="M 12.5,1 C 6.8467643,0.94037552 0.90011975,5.0932125 1,13 1.101235,21.014031 10.609264,28.121771 12.5,40 14.347762,28.312508 23.976551,21.962273 24,13 24.02093,5.0006739 18.153235,1.0596245 12.5,1 Z m 0.181641,7.3398438 c 2.494371,-3.473e-4 4.516847,2.0212542 4.517578,4.5156252 3.47e-4,2.495133 -2.022445,4.517925 -4.517578,4.517578 C 10.18727,17.372316 8.1656683,15.34984 8.1660156,12.855469 8.1667464,10.361861 10.188033,8.3405745 12.681641,8.3398438 Z"
58
+ id="path4138"
59
+ inkscape:connector-curvature="0"
60
+ sodipodi:nodetypes="sscssccccc" />
61
+ <path
62
+ style="fill:#1886d8;fill-opacity:0.85858583;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.53535354"
63
+ d="M 12.509053,0.90052064 C 6.855818,0.84089624 0.90917349,4.9937331 1.0090537,12.900521 c 0.101235,8.014031 9.6092633,15.121771 11.4999993,27 1.847762,-11.687492 11.476551,-18.037727 11.5,-27 0.02093,-7.9993265 -5.846765,-11.94037586 -11.5,-12.00000036 z m 0.181641,7.33984376 c 2.494371,-3.473e-4 4.516847,2.0212546 4.517578,4.5156256 3.47e-4,2.495133 -2.022445,4.517925 -4.517578,4.517578 C 10.196323,17.272837 8.174722,15.250361 8.1750693,12.75599 8.1758001,10.262382 10.197086,8.2410951 12.690694,8.2403644 Z"
64
+ id="path4138-3"
65
+ inkscape:connector-curvature="0"
66
+ sodipodi:nodetypes="sscssccccc" />
67
+ </svg>
@@ -0,0 +1,61 @@
1
+ # Core extension for vizualisation
2
+ #
3
+ String.prototype.camelize = () ->
4
+ array = jQuery.map this.split("_"), (word)->
5
+ word.charAt(0).toUpperCase() + word.slice(1)
6
+ return array.join()
7
+
8
+ String.prototype.repeat = (count) ->
9
+ return new Array(count + 1).join(this)
10
+
11
+ Math.magnitude = (number, step = 1) ->
12
+ value = Math.abs(number)
13
+ power = 0
14
+ if value > 1
15
+ while Math.pow(10, power + step) < value
16
+ power += step
17
+ else
18
+ while Math.pow(10, power - step) > value
19
+ power -= step
20
+ mag = Math.pow(10, power)
21
+ result =
22
+ power: power
23
+ magnitude: mag
24
+ base: number / mag
25
+
26
+ Math.round2 = (number, round = 1) ->
27
+ return round * Math.round(number / round)
28
+
29
+ Math.humanize = (value, power = 0) ->
30
+ return Math.round(value)
31
+ # return Math.round(value / Math.pow(10, power)) + "e#{power}"
32
+ size = Math.round(power / 3)
33
+ return Math.round(value / Math.pow(10, 3 * size)) + "pnµm KMGTPE"[size + 4]
34
+
35
+ Math.ceil2 = (number, round = 1) ->
36
+ return round * Math.ceil(number / round)
37
+
38
+ Math.floor2 = (number, round = 1) ->
39
+ return round * Math.floor(number / round)
40
+
41
+ # Returns logarithm value in given base (10 by default)
42
+ Math.logg = (value, base = 10) ->
43
+ return Math.log(value) / Math.log(base)
44
+
45
+ # Compute number of decimal
46
+ # Negative value is return if trailing zero are found.
47
+ # Ex: 200 => -2
48
+ # 0.12500 => 3
49
+ # 0.125 => 3
50
+ # 125 => 0
51
+ Math.decimalCount = (value) ->
52
+ return 0 if value == 0
53
+ count = 0
54
+ integersCount = Math.ceil(Math.logg(Math.floor(value)))
55
+ value /= Math.pow(10, integersCount)
56
+ while (value != Math.floor(value))
57
+ count += 1
58
+ value *= 10
59
+ break if count > 100
60
+ return count - integersCount
61
+
@@ -0,0 +1,23 @@
1
+ # Add sprockets directives below:
2
+
3
+ #= require jquery
4
+ #= require jquery-ui
5
+ #= require jquery_ujs
6
+ #= require turbolinks
7
+ #= require_self
8
+ #= require geographiclib
9
+ #= require leaflet.js.erb
10
+ #= require leaflet/draw
11
+ #= require leaflet/fullscreen
12
+ #= require leaflet/providers
13
+ #= require leaflet/heatmap
14
+ #= require leaflet/measure
15
+ #= require leaflet/easy-button
16
+ #= require leaflet/modal
17
+ #= require leaflet/label
18
+ #= require rbush
19
+ #= require autosize
20
+ #= require_tree ./leaflet
21
+ #= require foliage/leaf
22
+
23
+ this.Foliage = {};
@@ -0,0 +1,99 @@
1
+ class Foliage.Band
2
+
3
+ constructor: (@layer, @data, options = {}) ->
4
+ @items = []
5
+ property = @layer.reference
6
+ console.log "Property: ", property
7
+ previous = null
8
+ minValue = null
9
+ maxValue = null
10
+ for zone in @data
11
+ minValue ?= zone[property]
12
+ maxValue ?= zone[property]
13
+ minValue = zone[property] if minValue > zone[property]
14
+ maxValue = zone[property] if maxValue < zone[property]
15
+ if previous
16
+ @items.push
17
+ polygon: this.computeTrapez({x: previous.shape.coordinates[1], y: previous.shape.coordinates[0], w: previous.width}, {x: zone.shape.coordinates[1], y: zone.shape.coordinates[0], w: zone.width})
18
+ value: zone[property]
19
+ style:
20
+ stroke: false
21
+ fillOpacity: 1
22
+ previous = zone
23
+ if this.valid()
24
+ start = new Foliage.Color(options.startColor)
25
+ stop = new Foliage.Color(options.stopColor)
26
+ console.log(maxValue, minValue)
27
+ for item in @items
28
+ level = (item.value - minValue) / (maxValue - minValue)
29
+ item.style.fillColor = Foliage.Color.toString
30
+ red: start.red + (Math.round(stop.red - start.red) * level)
31
+ green: start.green + (Math.round(stop.green - start.green) * level)
32
+ blue: start.blue + (Math.round(stop.blue - start.blue) * level)
33
+ console.log "Bands computed"
34
+ else
35
+ console.warn "Invalid bands"
36
+
37
+ # Build layer as wanted
38
+ buildLayerGroup: (widget, globalStyle = {}) ->
39
+ group = []
40
+ for item in @items
41
+ edge = new L.polygon(item.polygon, item.style)
42
+ group.push(edge)
43
+ group
44
+
45
+ # Build HTML legend for given bands computed layer
46
+ buildLegend: () ->
47
+ html = "<div class='leaflet-legend-item' id='legend-#{@layer.name}'>"
48
+ html += "<h3>#{@layer.label}</h3>"
49
+ # html += "<div class='leaflet-legend-body leaflet-categories-scale'>"
50
+ # html += "<span class='leaflet-categories-items'>"
51
+ # html += "<span class='leaflet-categories-item'>"
52
+ # html += "<i class='leaflet-categories-sample' style='background-color: #{@items[0].fillColor};'></i>"
53
+ # html += " #{@layer.label}"
54
+ # html += "</span>"
55
+ # html += "</span>"
56
+ # html += "</div>"
57
+ html += "</div>"
58
+ return html
59
+
60
+ # Returns the item matching the given name
61
+ itemFor: (name) ->
62
+ back = null
63
+ @items.forEach (item, index, array) ->
64
+ back = item if item.name == name
65
+ return back
66
+
67
+ # Check if bands are valid
68
+ valid: () ->
69
+ @items.length > 0
70
+
71
+ # http://stackoverflow.com/questions/7854043/drawing-rectangle-between-two-points-with-arbitrary-width
72
+ computeTrapez: (a, b) ->
73
+ # Calculate a vector between start and end points
74
+ v =
75
+ x: b.x - a.x
76
+ y: b.y - a.y
77
+
78
+ # Then calculate a perpendicular to it (just swap X and Y coordinates)
79
+ p =
80
+ x: v.y # Use separate variable otherwise you overwrite X coordinate here
81
+ y: -v.x # Flip the sign of either the X or Y (edit by adam.wulf)
82
+
83
+ # Normalize that perpendicular
84
+ l = Math.sqrt(p.x * p.x + p.y * p.y); # That's length of perpendicular
85
+ n =
86
+ x: p.x / l
87
+ y: p.y / l # Now N is normalized perpendicular
88
+
89
+ # Calculate 4 points that form a rectangle by adding normalized perpendicular and multiplying it by half of the desired width
90
+ ar = (a.w / 2) * 9 / 1000000
91
+ br = (b.w / 2) * 9 / 1000000
92
+ r1 = new L.LatLng(a.x + n.x * ar, a.y + n.y * ar)
93
+ r2 = new L.LatLng(a.x - n.x * ar, a.y - n.y * ar)
94
+ r3 = new L.LatLng(b.x + n.x * br, b.y + n.y * br)
95
+ r4 = new L.LatLng(b.x - n.x * br, b.y - n.y * br)
96
+ return [r1, r2, r4, r3]
97
+
98
+
99
+ Foliage.registerLayerType "band", Foliage.Band
@@ -0,0 +1,77 @@
1
+ # Add sprockets directives below:
2
+ #= require foliage/gradient
3
+ #
4
+
5
+ class Foliage.Bubbles extends Foliage.Gradient
6
+
7
+ constructor: (@layer, @data, options = {}) ->
8
+ options.levelNumber ?= 5
9
+
10
+ super @data, @layer.reference, options
11
+
12
+ if this.valid()
13
+
14
+ # Compute radius
15
+ options.startRadius ?= 4
16
+ options.stopRadius ?= 24
17
+ start = options.startRadius
18
+ stop = options.stopRadius
19
+ for grade in @grades
20
+ level = grade.index / (@levelNumber - 1.0)
21
+ grade.radius = start + Math.round((stop - start) * level)
22
+ grade.fillColor = options.fillColor
23
+ grade.color = options.color
24
+ grade.weight = options.weight
25
+ grade.stroke = options.stroke
26
+ console.log "Radiuses computed"
27
+ else
28
+ console.warn "Invalid bubbles"
29
+
30
+ # Build layer as wanted
31
+ buildLayerGroup: (widget, globalStyle = {}) ->
32
+ group = []
33
+ # Shadow
34
+ for zone in @data
35
+ grade = this.gradeFor(zone[@layer.reference])
36
+ if grade.stroke
37
+ zoneStyle =
38
+ fillColor: grade.color
39
+ radius: grade.radius + grade.weight
40
+ stroke: false
41
+ fillOpacity: 0.8
42
+ group.push new L.CircleMarker(this._centroid(zone.shape), zoneStyle)
43
+ # Core
44
+ for zone in @data
45
+ grade = this.gradeFor(zone[@layer.reference])
46
+ zoneStyle =
47
+ fillColor: grade.fillColor
48
+ radius: grade.radius
49
+ stroke: false
50
+ fillOpacity: 1
51
+ zoneLayer = new L.CircleMarker(this._centroid(zone.shape), zoneStyle)
52
+ widget._bindPopup(zoneLayer, zone)
53
+ group.push(zoneLayer)
54
+ group
55
+
56
+ # Build HTML legend for given bubbles computed layer
57
+ buildLegend: () ->
58
+ html = "<div class='leaflet-legend-item' id='legend-#{@layer.name}'>"
59
+ html += "<h3>#{@layer.label}</h3>"
60
+ html += "<div class='leaflet-legend-body leaflet-bubbles-scale'>"
61
+ html += "<span class='min-value'>#{@grades[0].minLabel}</span>"
62
+ html += "<span class='leaflet-bubbles-grades'>"
63
+ for grade in @grades
64
+ html += "<i class='leaflet-bubbles-grade' style='width: #{2 * grade.radius}px; height: #{2 * grade.radius}px; background-color: #{grade.fillColor}; border-width: #{grade.weight}px; border-color: #{grade.color}' title='#{grade.minLabel} ~ #{grade.maxLabel}'></i>"
65
+ html += "</span>"
66
+ html += "<span class='max-value'>#{@grades[@levelNumber - 1].maxLabel}</span>"
67
+ html += "</div>"
68
+ html += "</div>"
69
+ return html
70
+
71
+ # Compute a centroid based on bounds
72
+ # The point can be out of the surface...
73
+ _centroid: (shape) ->
74
+ geojson = new L.GeoJSON(shape)
75
+ return geojson.getBounds().getCenter()
76
+
77
+ Foliage.registerLayerType "bubbles", Foliage.Bubbles
@@ -0,0 +1,70 @@
1
+ class Foliage.Categories
2
+
3
+ constructor: (@layer, @data, options = {}) ->
4
+ @items = []
5
+ property = @layer.reference
6
+ for zone in @data
7
+ unless this.itemFor(zone[property])
8
+ @items.push
9
+ name: zone[property],
10
+ color: zone['shapeColor']
11
+
12
+ if this.valid()
13
+ @items = @items.sort (a, b) ->
14
+ a.name > b.name
15
+ @colors = options.colors ? []
16
+ if @items.length > @colors.length
17
+ for x in [@colors.length..@items.length]
18
+ @colors.push(options.parent.options.colors[x] ? "#000000")
19
+ for item, index in @items
20
+ if item.color?
21
+ item.fillColor = item.color
22
+ else
23
+ item.fillColor = @colors[index]
24
+
25
+ console.log "Categories computed"
26
+ else
27
+ console.warn "Invalid categories"
28
+
29
+ # Build layer as wanted
30
+ buildLayerGroup: (widget, globalStyle = {}) ->
31
+ group = []
32
+ for zone in @data
33
+ zoneStyle =
34
+ fillColor: this.itemFor(zone[@layer.reference]).fillColor
35
+ zoneLayer = new L.GeoJSON(zone.shape, $.extend(true, {}, globalStyle, zoneStyle))
36
+ widget._bindPopup(zoneLayer, zone)
37
+ unless @layer.withoutGhostLabel
38
+ label = new L.GhostLabel(className: 'leaflet-ghost-label', toBack: false).setContent(zone.name).toCentroidOfBounds(zoneLayer.getLayers()[0].getLatLngs())
39
+ widget.ghostLabelCluster.bind label, zoneLayer.getLayers()[0]
40
+ group.push(zoneLayer)
41
+ group
42
+
43
+ # Build HTML legend for given categories computed layer
44
+ buildLegend: () ->
45
+ html = "<div class='leaflet-legend-item' id='legend-#{@layer.name}'>"
46
+ html += "<h3>#{@layer.label}</h3>"
47
+ html += "<div class='leaflet-legend-body leaflet-categories-scale'>"
48
+ html += "<span class='leaflet-categories-items'>"
49
+ for name, item of @items
50
+ html += "<span class='leaflet-categories-item'>"
51
+ html += "<i class='leaflet-categories-sample' style='background-color: #{item.fillColor};'></i>"
52
+ html += " <span class='leaflet-categories-item_label'>#{item.name}</span>"
53
+ html += "</span>"
54
+ html += "</span>"
55
+ html += "</div>"
56
+ html += "</div>"
57
+ return html
58
+
59
+ # Returns the item matching the given name
60
+ itemFor: (name) ->
61
+ back = null
62
+ @items.forEach (item, index, array) ->
63
+ back = item if item.name == name
64
+ return back
65
+
66
+ # Check if categories are valid
67
+ valid: () ->
68
+ @items.length > 0
69
+
70
+ Foliage.registerLayerType "categories", Foliage.Categories