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
@@ -0,0 +1,76 @@
1
+ # Foliage.Paths class
2
+ # displays crumbs by intervention as a path
3
+ #
4
+ # @data is an array of hashes containing info to display
5
+ # @layer is the layer name
6
+ #
7
+ # ==== examples
8
+ #
9
+ # @data is an array of hashes built according to the following model:
10
+ # * minimal example of a hash representing a crumb:
11
+ # item {
12
+ # name: <intervention name>, # may be the date, the doer's name,
13
+ # # whatever you want as long as all the crumbs
14
+ # # for a given intervention have the same one.
15
+ # # This is what is called in the
16
+ # # FoliageHelper to build the legend if
17
+ # # you wrote something like:
18
+ # # = foliage do |leaf|
19
+ # # - leaf.serie :crumbs, my_array_of_crumbs_hashes
20
+ # # - leaf.paths :name, :crumbs
21
+ # # :name being the @layer parameter the constructor requires.
22
+ # nature: crumb.nature, # proper to the crumb. May be one of the natures
23
+ # # enumerated in Crumb model.
24
+ # # this option is used to display particular points
25
+ # # bigger and to change the path opacity for parts
26
+ # # that correspond to actual works (points between a
27
+ # # hard_start) and a hard_stop crumb
28
+ # shape: crumb.geolocation, # proper to the crumb. contains the actual crumb
29
+ # # location as a Charta::Geometry object.
30
+ # # This is what is used to draw the crumb on the map
31
+ # }
32
+ class Foliage.Path
33
+
34
+ constructor: (@layer, @data, @options = {}) ->
35
+ if this.valid()
36
+ @options.color ?= Foliage.colors[0]
37
+ @options.fillColor ?= @options.color
38
+ console.log "Paths computed", @options
39
+ else
40
+ console.warn "Invalid paths"
41
+
42
+ # Build layer as wanted
43
+ buildLayerGroup: (widget, globalStyle = {}) ->
44
+ group = []
45
+ for crumb in @data
46
+ crumbLayer = new L.circleMarker(new L.geoJson(crumb.shape).getBounds().getCenter(), $.extend(true, {}, globalStyle, @options, {className: "crumb crumb-#{crumb.name}"}))
47
+ widget._bindPopup(crumbLayer, crumb)
48
+ group.push(crumbLayer)
49
+ previous_crumb = @data[@data.indexOf(crumb) - 1]
50
+ if previous_crumb
51
+ points = []
52
+ points.push(new L.geoJson(previous_crumb.shape).getBounds().getCenter())
53
+ points.push(new L.geoJson(crumb.shape).getBounds().getCenter())
54
+ crumbLayer = new L.polyline(points, $.extend(true, {}, globalStyle, @options))
55
+ group.push(crumbLayer)
56
+ return group
57
+
58
+ # Build HTML legend for given paths computed layer
59
+ buildLegend: () ->
60
+ html = "<div class='leaflet-legend-item' id='legend-#{@layer.name}'>"
61
+ html += "<div class='leaflet-legend-body leaflet-categories-scale'>"
62
+ html += "<span class='leaflet-categories-items'>"
63
+ html += "<span class='leaflet-categories-item'>"
64
+ html += "<i class='leaflet-categories-sample' style='background-color: #{@options.color};'></i>"
65
+ html += " #{@layer.label}"
66
+ html += "</span>"
67
+ html += "</span>"
68
+ html += "</div>"
69
+ html += "</div>"
70
+ return html
71
+
72
+ # Check if paths are valid
73
+ valid: () ->
74
+ true
75
+
76
+ Foliage.registerLayerType "path", Foliage.Path
@@ -0,0 +1,131 @@
1
+ # Foliage.Paths class
2
+ # displays crumbs by intervention as a path
3
+ #
4
+ # @data is an array of hashes containing info to display
5
+ # @layer is the layer name
6
+ #
7
+ # ==== examples
8
+ #
9
+ # @data is an array of hashes built according to the following model:
10
+ # * minimal example of a hash representing a crumb:
11
+ # item {
12
+ # name: <intervention name>, # may be the date, the doer's name,
13
+ # # whatever you want as long as all the crumbs
14
+ # # for a given intervention have the same one.
15
+ # # This is what is called in the
16
+ # # FoliageHelper to build the legend if
17
+ # # you wrote something like:
18
+ # # = foliage do |leaf|
19
+ # # - leaf.serie :crumbs, my_array_of_crumbs_hashes
20
+ # # - leaf.paths :name, :crumbs
21
+ # # :name being the @layer parameter the constructor requires.
22
+ # nature: crumb.nature, # proper to the crumb. May be one of the natures
23
+ # # enumerated in Crumb model.
24
+ # # this option is used to display particular points
25
+ # # bigger and to change the path opacity for parts
26
+ # # that correspond to actual works (points between a
27
+ # # hard_start) and a hard_stop crumb
28
+ # shape: crumb.geolocation, # proper to the crumb. contains the actual crumb
29
+ # # location as a Charta::Geometry object.
30
+ # # This is what is used to draw the crumb on the map
31
+ # }
32
+ class Foliage.Paths
33
+
34
+ constructor: (@layer, @data, options = {}) ->
35
+ @items = []
36
+ property = @layer.reference
37
+ for crumb in @data
38
+ unless this.itemFor(crumb[property])
39
+ @items.push
40
+ name: crumb[property]
41
+
42
+ if this.valid()
43
+ @items = @items.sort (a, b) ->
44
+ a.name > b.name
45
+ @colors = options.colors ? []
46
+ if @items.length > @colors.length
47
+ for x in [@colors.length..@items.length]
48
+ @colors.push(Foliage.colors[x] ? "#000000")
49
+ for item, index in @items
50
+ item.fillColor = @colors[index]
51
+
52
+ console.log "Paths computed"
53
+ else
54
+ console.warn "Invalid paths"
55
+
56
+ # Build layer as wanted
57
+ buildLayerGroup: (widget, globalStyle = {}) ->
58
+ group = []
59
+ # defining styles
60
+ strokeWidth = 4
61
+ crumbStyle =
62
+ radius: strokeWidth
63
+ stroke: true
64
+ weight: strokeWidth/2
65
+ color: "#000000"
66
+ fillColor: "#FFFFFF"
67
+ opacity: 1
68
+ lineStyle =
69
+ weight: strokeWidth
70
+ stroke: true
71
+ color: this.itemFor(@data[0][@layer.reference]).fillColor
72
+ fillColor: "rgba(0,0,0,0)"
73
+ opacity: 1
74
+
75
+ # drawing line
76
+ points = []
77
+ current_name = @data[0].name
78
+ current_color = this.itemFor(@data[0][@layer.reference]).fillColor
79
+ for crumb in @data
80
+ if crumb.name != current_name
81
+ lineStyle.color = current_color
82
+ lineLayer = new L.polyline(points, $.extend(true, {}, globalStyle, lineStyle))
83
+ group.push(lineLayer)
84
+ points = []
85
+ current_name = crumb.name
86
+ current_color = this.itemFor(crumb[@layer.reference]).fillColor
87
+ points.push(new L.geoJson(crumb.shape).getBounds().getCenter())
88
+ if points.length > 0
89
+ lineStyle.color = current_color
90
+ lineLayer = new L.polyline(points, $.extend(true, {}, globalStyle, lineStyle))
91
+ group.push(lineLayer)
92
+ # drawing circles
93
+ for crumb in @data
94
+ crumbStyle.color= this.itemFor(crumb[@layer.reference]).fillColor
95
+ if crumb.nature == 'hard_start'
96
+ crumbStyle.fillColor = "#000000"
97
+ if crumb.nature == 'hard_stop'
98
+ crumbStyle.fillColor = "#FFFFFF"
99
+ crumbLayer = new L.circleMarker(new L.geoJson(crumb.shape).getBounds().getCenter(), $.extend(true, {}, globalStyle, crumbStyle))
100
+ widget._bindPopup(crumbLayer, crumb)
101
+ group.push(crumbLayer)
102
+ group
103
+
104
+ # Build HTML legend for given paths computed layer
105
+ buildLegend: () ->
106
+ html = "<div class='leaflet-legend-item' id='legend-#{@layer.name}'>"
107
+ html += "<h3>#{@layer.label}</h3>"
108
+ html += "<div class='leaflet-legend-body leaflet-categories-scale'>"
109
+ html += "<span class='leaflet-categories-items'>"
110
+ for name, item of @items
111
+ html += "<span class='leaflet-categories-item'>"
112
+ html += "<i class='leaflet-categories-sample' style='background-color: #{item.fillColor};'></i>"
113
+ html += " #{item.name}"
114
+ html += "</span>"
115
+ html += "</span>"
116
+ html += "</div>"
117
+ html += "</div>"
118
+ return html
119
+
120
+ # Returns the item matching the given name
121
+ itemFor: (name) ->
122
+ back = null
123
+ @items.forEach (item, index, array) ->
124
+ back = item if item.name == name
125
+ return back
126
+
127
+ # Check if paths are valid
128
+ valid: () ->
129
+ @items.length > 0
130
+
131
+ Foliage.registerLayerType "paths", Foliage.Paths
@@ -0,0 +1,83 @@
1
+ class Foliage.PointGroup
2
+
3
+ constructor: (@layer, @data, @options = {}) ->
4
+ @items = []
5
+ console.log "Layer: ", @layer
6
+ for zone in @data
7
+ lnglat = zone.shape.coordinates
8
+ @items.push
9
+ name: zone.name
10
+ point: [lnglat[1], lnglat[0]]
11
+ radius: zone.radius ? @options.radius
12
+ group: zone.group
13
+ fillColor: zone.shapeColor
14
+ popup: zone.popup
15
+ sensorId: zone.sensorId
16
+ if this.valid()
17
+ @items = @items.sort (a, b) ->
18
+ a.name > b.name
19
+ @groups = {}
20
+ for {group, name, fillColor} in @items
21
+ @groups[group] or= fillColor
22
+ console.log "Point group computed"
23
+ else
24
+ console.warn "Invalid categories"
25
+
26
+ # Build layer as wanted
27
+ buildLayerGroup: (widget, globalStyle = {}) ->
28
+ group = []
29
+ # Shadow
30
+ if @options.stroke
31
+ for zone in @items
32
+ zoneStyle =
33
+ fillColor: zone.color ? @options.color
34
+ radius: (zone.radius ? @options.radius) + @options.weight
35
+ stroke: false
36
+ fillOpacity: 0.8
37
+ console.log zone.point
38
+ shadow = new L.circleMarker(zone.point, zoneStyle)
39
+ shadow.markerSensorId = zone.sensorId
40
+ group.push shadow
41
+ # Core
42
+ for zone in @items
43
+ console.log zone
44
+ zoneStyle =
45
+ fillColor: zone.fillColor ? @options.fillColor
46
+ radius: zone.radius ? @options.radius
47
+ stroke: false
48
+ fillOpacity: 1
49
+ console.log zoneStyle
50
+ zoneLayer = new L.circleMarker(zone.point, zoneStyle)
51
+ zoneLayer.sensorId = zone.sensorId
52
+ widget._bindPopup(zoneLayer, zone)
53
+ group.push(zoneLayer)
54
+ group
55
+
56
+ # Build HTML legend for given points 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-categories-scale'>"
61
+ html += "<span class='leaflet-categories-items'>"
62
+ for group in Object.keys(@groups)
63
+ html += "<span class='leaflet-categories-item'>"
64
+ html += "<i class='leaflet-categories-sample' style='background-color: #{@groups[group]};'></i>"
65
+ html += " <span class='leaflet-categories-item_label'>#{group}</span>"
66
+ html += "</span>"
67
+ html += "</span>"
68
+ html += "</div>"
69
+ html += "</div>"
70
+ return html
71
+
72
+ # Returns the item matching the given name
73
+ itemFor: (name) ->
74
+ back = null
75
+ @items.forEach (item, index, array) ->
76
+ back = item if item.name == name
77
+ return back
78
+
79
+ # Check if categories are valid
80
+ valid: () ->
81
+ @items.length > 0
82
+
83
+ Foliage.registerLayerType "point_group", Foliage.PointGroup
@@ -0,0 +1,79 @@
1
+ class Foliage.Points
2
+
3
+ constructor: (@layer, @data, @options = {}) ->
4
+ @items = []
5
+ console.log "Layer: ", @layer
6
+ for zone in @data
7
+ lnglat = zone.shape.coordinates
8
+ @items.push
9
+ name: zone.name
10
+ point: [lnglat[1], lnglat[0]]
11
+ radius: zone.radius ? @options.radius
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(Foliage.colors[x] ? "#000000")
19
+ for item, index in @items
20
+ item.fillColor = @colors[index]
21
+ console.log "Points computed"
22
+ else
23
+ console.warn "Invalid categories"
24
+
25
+ # Build layer as wanted
26
+ buildLayerGroup: (widget, globalStyle = {}) ->
27
+ group = []
28
+ # Shadow
29
+ if @options.stroke
30
+ for zone in @items
31
+ zoneStyle =
32
+ fillColor: zone.color ? @options.color
33
+ radius: (zone.radius ? @options.radius) + @options.weight
34
+ stroke: false
35
+ fillOpacity: 0.8
36
+ console.log zone.point
37
+ group.push new L.circleMarker(zone.point, zoneStyle)
38
+ # Core
39
+ for zone in @items
40
+ console.log zone
41
+ zoneStyle =
42
+ fillColor: zone.fillColor ? @options.fillColor
43
+ radius: zone.radius ? @options.radius
44
+ stroke: false
45
+ fillOpacity: 1
46
+ console.log zoneStyle
47
+ zoneLayer = new L.circleMarker(zone.point, zoneStyle)
48
+ widget._bindPopup(zoneLayer, zone)
49
+ group.push(zoneLayer)
50
+ group
51
+
52
+ # Build HTML legend for given points computed layer
53
+ buildLegend: () ->
54
+ html = "<div class='leaflet-legend-item' id='legend-#{@layer.name}'>"
55
+ html += "<h3>#{@layer.label}</h3>"
56
+ html += "<div class='leaflet-legend-body leaflet-categories-scale'>"
57
+ html += "<span class='leaflet-categories-items'>"
58
+ for name, item of @items
59
+ html += "<span class='leaflet-categories-item'>"
60
+ html += "<i class='leaflet-categories-sample' style='background-color: #{item.fillColor};'></i>"
61
+ html += " #{item.name}"
62
+ html += "</span>"
63
+ html += "</span>"
64
+ html += "</div>"
65
+ html += "</div>"
66
+ return html
67
+
68
+ # Returns the item matching the given name
69
+ itemFor: (name) ->
70
+ back = null
71
+ @items.forEach (item, index, array) ->
72
+ back = item if item.name == name
73
+ return back
74
+
75
+ # Check if categories are valid
76
+ valid: () ->
77
+ @items.length > 0
78
+
79
+ Foliage.registerLayerType "points", Foliage.Points
@@ -0,0 +1,35 @@
1
+ class Foliage.Simple
2
+
3
+ constructor: (@layer, @data, @options = {}) ->
4
+
5
+ # Build layer as wanted
6
+ buildLayerGroup: (widget, globalStyle = {}) ->
7
+ group = []
8
+ for zone in @data
9
+ zoneLayer = new L.GeoJSON(zone.shape, globalStyle)
10
+ label = new L.GhostLabel(className: 'leaflet-ghost-label', toBack: false).setContent(zone.name).toCentroidOfBounds(zoneLayer.getLayers()[0].getLatLngs())
11
+ widget.ghostLabelCluster.bind label, zoneLayer.getLayers()[0]
12
+ widget._bindPopup(zoneLayer, zone)
13
+ group.push(zoneLayer)
14
+ group
15
+
16
+ # Build HTML legend for given categories computed layer
17
+ buildLegend: () ->
18
+ html = "<div class='leaflet-legend-item' id='legend-#{@layer.name}'>"
19
+ # html += "<h3>#{@layer.label}</h3>"
20
+ html += "<div class='leaflet-legend-body leaflet-categories-scale'>"
21
+ html += "<span class='leaflet-categories-items'>"
22
+ html += "<span class='leaflet-categories-item'>"
23
+ html += "<i class='leaflet-categories-sample' style='background-color: #{@layer.fillColor || @options.parent.options.layerDefaults[@layer.type].fillColor };'></i>"
24
+ html += " <span class='leaflet-categories-item_label'>#{@layer.label}</span>"
25
+ html += "</span>"
26
+ html += "</span>"
27
+ html += "</div>"
28
+ html += "</div>"
29
+ return html
30
+
31
+ # Check if categories are valid
32
+ valid: () ->
33
+ true
34
+
35
+ Foliage.registerLayerType "simple", Foliage.Simple
@@ -0,0 +1,23 @@
1
+ L.GeographicUtil = L.extend L.GeographicUtil || {},
2
+ geod: GeographicLib.Geodesic.WGS84
3
+
4
+ # Use Karney distance formula
5
+ # ([lat, lng], [lat, lng]) -> Number (in meters)
6
+ distance: (a, b) ->
7
+ r = @geod.Inverse(a[0], a[1], b[0], b[1])
8
+ r.s12.toFixed(3)
9
+
10
+ Polygon: (points) -> # (Array of [lat,lng] pair)
11
+ @geod = GeographicLib.Geodesic.WGS84
12
+ @poly = @geod.Polygon(false)
13
+ for point in points
14
+ @poly.AddPoint point[0], point[1]
15
+
16
+ @poly = @poly.Compute(false, true)
17
+ return
18
+
19
+ L.GeographicUtil.Polygon.prototype =
20
+ perimeter: ->
21
+ @poly.perimeter
22
+ area: ->
23
+ Math.abs @poly.area
@@ -0,0 +1,100 @@
1
+ ###
2
+ # Extend L.Label to provide a label on centroid, calculated from a L.Latlng[]
3
+ # options:
4
+ # toBack {boolean} if true, label is set to objectsPane, allowing to be covered by higher level pane
5
+ # opacity: {string} ([0..1] | 'inherit') inherit allows to use opacity in your class. Default: 'inherit'
6
+ ###
7
+ L.GhostLabel = L.Label.extend
8
+ __initialize: L.Label::initialize
9
+ _onAdd: L.Label.prototype.onAdd
10
+ __updateContent: L.Label.prototype._updateContent
11
+ __setOpacity: L.Label::setOpacity
12
+
13
+ initialize: (options, source) ->
14
+ options.opacity ||= 'inherit'
15
+
16
+ @__initialize.apply @, arguments
17
+
18
+ ###
19
+ # Set the latLng[] to calculate the centroid
20
+ ###
21
+ toCentroidOfBounds: (latLngs) ->
22
+ # To center of bounds if centroid can't be calculated during onAdd
23
+ @_latlng = L.latLngBounds(latLngs).getCenter()
24
+ @_latLngs = latLngs
25
+ return this
26
+
27
+ onAdd: (map) ->
28
+ # Don't hide labels on click
29
+ @options.noHide = true
30
+
31
+ if @options.toBack
32
+ @options.pane = 'objectsPane'
33
+
34
+ @_onAdd.apply this, arguments
35
+
36
+ map.on 'zoomend', @_onZoomEnd, @
37
+
38
+ if @options.toBack
39
+ # ZIndex 3 is default index of objectsPane
40
+ @updateZIndex '3'
41
+
42
+ @_updatePosition()
43
+ return
44
+
45
+ setOpacity: (opacity) ->
46
+ unless opacity is 'inherit'
47
+ @__setOpacity.call @, opacity
48
+
49
+ getLatLng: ->
50
+ @_latlng
51
+
52
+ _onZoomEnd: (e) ->
53
+ @getCenter(e.target)
54
+
55
+ getCenter: (map)->
56
+ if @_latLngs
57
+ poly = L.polygon(@_latLngs)
58
+ poly._map = @_map || map
59
+ @_latlng = poly.__getCenter()
60
+
61
+ @_latlng
62
+
63
+
64
+ ###
65
+ # Override to set position on pos, considering label center
66
+ ###
67
+ _setPosition: (pos) ->
68
+ map = @_map
69
+ container = @_container
70
+ labelWidth = @_labelWidth
71
+ labelHeight = @_labelHeight || 0
72
+
73
+ pos = pos.add(L.point(-labelWidth/2, -labelHeight/2))
74
+ L.DomUtil.setPosition container, pos
75
+ return
76
+
77
+ ###
78
+ # Override to set position on pos, considering label center
79
+ ###
80
+ _updateContent: ->
81
+ @__updateContent.call this
82
+ @_labelHeight = @_container.offsetHeight if @_container
83
+
84
+
85
+ L.extendedMethods =
86
+ # Allow to be updated
87
+ bindGhostLabel: (object, options) ->
88
+
89
+ if !@label
90
+ @label = object
91
+
92
+ if !@_showLabelAdded
93
+ @on 'remove', @_hideLabel, @
94
+
95
+ @_showLabelAdded = true
96
+ return
97
+
98
+ L.Polygon.include L.extendedMethods
99
+ L.FeatureGroup.include L.extendedMethods
100
+