foliage 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +9 -0
- data/app/assets/images/.keep +0 -0
- data/app/assets/images/map/marker/icon-2x.png +0 -0
- data/app/assets/images/map/marker/icon.png +0 -0
- data/app/assets/images/map/marker/icon.svg +67 -0
- data/app/assets/images/map/marker/shadow.png +0 -0
- data/app/assets/javascripts/core_ext.js.coffee +61 -0
- data/app/assets/javascripts/foliage.js.coffee +23 -0
- data/app/assets/javascripts/foliage/band.js.coffee +99 -0
- data/app/assets/javascripts/foliage/bubbles.js.coffee +77 -0
- data/app/assets/javascripts/foliage/categories.js.coffee +70 -0
- data/app/assets/javascripts/foliage/choropleth.js.coffee +51 -0
- data/app/assets/javascripts/foliage/color.js.coffee +39 -0
- data/app/assets/javascripts/foliage/gradient.js.coffee +72 -0
- data/app/assets/javascripts/foliage/heatmap.js.coffee +49 -0
- data/app/assets/javascripts/foliage/leaf.js.coffee +422 -0
- data/app/assets/javascripts/foliage/path.js.coffee +76 -0
- data/app/assets/javascripts/foliage/paths.js.coffee +131 -0
- data/app/assets/javascripts/foliage/point_group.js.coffee +83 -0
- data/app/assets/javascripts/foliage/points.js.coffee +79 -0
- data/app/assets/javascripts/foliage/simple.js.coffee +35 -0
- data/app/assets/javascripts/leaflet/geographic_util.js.coffee +23 -0
- data/app/assets/javascripts/leaflet/ghost_label.js.coffee +100 -0
- data/app/assets/javascripts/leaflet/ghost_label_cluster.js.coffee +192 -0
- data/app/assets/javascripts/leaflet/layers_scheduler.js.coffee +57 -0
- data/app/assets/javascripts/leaflet/reactive_measure.js.coffee +414 -0
- data/app/assets/stylesheets/all.scss +16 -0
- data/app/assets/stylesheets/application.css +15 -0
- data/app/assets/stylesheets/compass/reset.scss +3 -0
- data/app/assets/stylesheets/compass/reset/utilities.scss +142 -0
- data/app/assets/stylesheets/leaflet.scss +1093 -0
- data/app/assets/stylesheets/leaflet/label.scss +40 -0
- data/app/assets/stylesheets/leaflet/tooltip.scss +42 -0
- data/app/assets/stylesheets/mixins.scss +131 -0
- data/app/assets/stylesheets/reset.scss +89 -0
- data/app/assets/stylesheets/variables.scss +47 -0
- data/app/helpers/foliage_helper.rb +23 -0
- data/lib/foliage.rb +9 -0
- data/lib/foliage/leaf.rb +235 -0
- data/lib/foliage/rails.rb +2 -0
- data/lib/foliage/rails/engine.rb +7 -0
- data/lib/foliage/rails/integration.rb +8 -0
- data/lib/foliage/version.rb +3 -0
- data/vendor/assets/javascripts/.keep +0 -0
- data/vendor/assets/javascripts/autosize.js +211 -0
- data/vendor/assets/javascripts/geographiclib.js +3074 -0
- data/vendor/assets/javascripts/leaflet.js.erb +9175 -0
- data/vendor/assets/javascripts/leaflet/draw.js +3573 -0
- data/vendor/assets/javascripts/leaflet/easy-button.js +366 -0
- data/vendor/assets/javascripts/leaflet/fullscreen.js +162 -0
- data/vendor/assets/javascripts/leaflet/heatmap.js +142 -0
- data/vendor/assets/javascripts/leaflet/label.js +545 -0
- data/vendor/assets/javascripts/leaflet/measure.js +6966 -0
- data/vendor/assets/javascripts/leaflet/modal.js +364 -0
- data/vendor/assets/javascripts/leaflet/providers.js +479 -0
- data/vendor/assets/javascripts/rbush.js +621 -0
- data/vendor/assets/stylesheets/.keep +0 -0
- data/vendor/assets/stylesheets/bootstrap/mixins.scss +55 -0
- data/vendor/assets/stylesheets/bootstrap/variables.scss +10 -0
- data/vendor/assets/stylesheets/leaflet.scss +479 -0
- data/vendor/assets/stylesheets/leaflet/draw.scss +282 -0
- data/vendor/assets/stylesheets/leaflet/easy-button.scss +56 -0
- data/vendor/assets/stylesheets/leaflet/fullscreen.scss +2 -0
- data/vendor/assets/stylesheets/leaflet/measure.scss +168 -0
- data/vendor/assets/stylesheets/leaflet/modal.scss +85 -0
- metadata +171 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
.leaflet-label {
|
2
|
+
color: black;
|
3
|
+
font-size: 14px;
|
4
|
+
display: block;
|
5
|
+
padding: 0.5*10px 10px;
|
6
|
+
position: absolute;
|
7
|
+
pointer-events: none;
|
8
|
+
white-space: nowrap;
|
9
|
+
z-index: 1;
|
10
|
+
text-shadow: 0 0 2px white;
|
11
|
+
text-shadow: 2px 0 0 #fff, -2px 0 0 #fff, 0 2px 0 #fff, 0 -2px 0 #fff, 1px 1px #fff, -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff;
|
12
|
+
&.leaflet-clickable {
|
13
|
+
cursor: pointer;
|
14
|
+
pointer-events: auto;
|
15
|
+
}
|
16
|
+
|
17
|
+
&:before, &:after {
|
18
|
+
border-top: 6px solid transparent;
|
19
|
+
border-bottom: 6px solid transparent;
|
20
|
+
content: none;
|
21
|
+
position: absolute;
|
22
|
+
top: 5px;
|
23
|
+
}
|
24
|
+
|
25
|
+
&:before {
|
26
|
+
border-right: 6px solid black;
|
27
|
+
border-right-color: inherit;
|
28
|
+
left: -10px;
|
29
|
+
}
|
30
|
+
|
31
|
+
&:after {
|
32
|
+
border-left: 6px solid black;
|
33
|
+
border-left-color: inherit;
|
34
|
+
right: -10px;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
.leaflet-label-right:before, .leaflet-label-left:after {
|
39
|
+
content: "";
|
40
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
.leaflet-draw-tooltip-left {
|
2
|
+
background: rgb(54, 54, 54);
|
3
|
+
background: rgba(0, 0, 0, 0.5);
|
4
|
+
border: 1px solid transparent;
|
5
|
+
position: absolute;
|
6
|
+
visibility: hidden;
|
7
|
+
white-space: nowrap;
|
8
|
+
z-index: 6;
|
9
|
+
&:before {
|
10
|
+
border: none !important;
|
11
|
+
}
|
12
|
+
&:after {
|
13
|
+
border-left: 6px solid black;
|
14
|
+
border-left-color: rgba(0, 0, 0, 0.5);
|
15
|
+
border-top: 6px solid transparent;
|
16
|
+
border-bottom: 6px solid transparent;
|
17
|
+
content: "";
|
18
|
+
position: absolute;
|
19
|
+
top: 7px;
|
20
|
+
left: 100%;
|
21
|
+
}
|
22
|
+
span {
|
23
|
+
color: inherit;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
.leaflet-draw-tooltip-measure {
|
28
|
+
&.perimeter {
|
29
|
+
}
|
30
|
+
&.area {
|
31
|
+
padding-left: 10px
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
.reactive-measure-control {
|
36
|
+
background: rgba(255,255,255, 0.6);
|
37
|
+
padding: 0 10px;
|
38
|
+
|
39
|
+
&.selection {
|
40
|
+
background: rgba(mix(white, red), 0.5);
|
41
|
+
}
|
42
|
+
}
|
@@ -0,0 +1,131 @@
|
|
1
|
+
@import "bootstrap/mixins";
|
2
|
+
|
3
|
+
@mixin calc($property, $expression) {
|
4
|
+
#{$property}: -webkit-calc(#{$expression});
|
5
|
+
#{$property}: -khtml-calc(#{$expression});
|
6
|
+
#{$property}: -moz-calc(#{$expression});
|
7
|
+
#{$property}: -ms-calc(#{$expression});
|
8
|
+
#{$property}: -o-calc(#{$expression});
|
9
|
+
#{$property}: calc(#{$expression});
|
10
|
+
}
|
11
|
+
|
12
|
+
@mixin prefixed-property($property, $value) {
|
13
|
+
-webkit-#{$property}: $value;
|
14
|
+
-khtml-#{$property}: $value;
|
15
|
+
-moz-#{$property}: $value;
|
16
|
+
-ms-#{$property}: $value;
|
17
|
+
-o-#{$property}: $value;
|
18
|
+
#{$property}: $value;
|
19
|
+
}
|
20
|
+
|
21
|
+
@mixin border-radius($radius) {
|
22
|
+
@include prefixed-property(border-radius, $radius);
|
23
|
+
}
|
24
|
+
|
25
|
+
@mixin inline-block($alignment: middle) {
|
26
|
+
display: -moz-inline-stack;
|
27
|
+
display: inline-block;
|
28
|
+
@if $alignment and $alignment != none {
|
29
|
+
vertical-align: $alignment;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
@mixin basic-icon($font-size: null) {
|
35
|
+
font-family: Agric;
|
36
|
+
font-weight: normal;
|
37
|
+
font-style: normal;
|
38
|
+
text-decoration: inherit;
|
39
|
+
-webkit-font-smoothing: antialiased;
|
40
|
+
width: auto;
|
41
|
+
height: auto;
|
42
|
+
background-image: none;
|
43
|
+
background-position: 0% 0%;
|
44
|
+
background-repeat: repeat;
|
45
|
+
margin-top: 0;
|
46
|
+
@if $font-size != null {
|
47
|
+
font-size: $font-size;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
@mixin is-icon($font-size: round(1.2 * $fs-normal)) {
|
52
|
+
@include basic-icon($font-size);
|
53
|
+
vertical-align: middle;
|
54
|
+
}
|
55
|
+
|
56
|
+
@mixin use-icon($name) {
|
57
|
+
&::before { content: icon-character($name); }
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
@mixin define-right-property($base-name, $value) {
|
62
|
+
html & { #{$base-name}-right: $value; }
|
63
|
+
html[dir="ltr"] & { #{$base-name}-right: $value; }
|
64
|
+
html[dir="rtl"] & { #{$base-name}-left: $value; }
|
65
|
+
}
|
66
|
+
|
67
|
+
@mixin define-left-property($base-name, $value) {
|
68
|
+
html & { #{$base-name}-left: $value; }
|
69
|
+
html[dir="ltr"] & { #{$base-name}-left: $value; }
|
70
|
+
html[dir="rtl"] & { #{$base-name}-right: $value; }
|
71
|
+
}
|
72
|
+
|
73
|
+
@mixin margin-right($value) { @include define-right-property(margin, $value); }
|
74
|
+
@mixin margin-left($value) { @include define-left-property(margin, $value); }
|
75
|
+
|
76
|
+
@mixin text-align($dir) {
|
77
|
+
@if $dir == right {
|
78
|
+
html & { text-align: right; }
|
79
|
+
html[dir="ltr"] & { text-align: right; }
|
80
|
+
html[dir="rtl"] & { text-align: left; }
|
81
|
+
} @else if $dir == left {
|
82
|
+
html & { text-align: left; }
|
83
|
+
html[dir="ltr"] & { text-align: left; }
|
84
|
+
html[dir="rtl"] & { text-align: right; }
|
85
|
+
} @else {
|
86
|
+
html &, html[dir="ltr"] &, html[dir="rtl"] & { text-align: $dir; }
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
@mixin float($dir) {
|
91
|
+
@if $dir == right {
|
92
|
+
html & { float: right; }
|
93
|
+
html[dir="ltr"] & { float: right; }
|
94
|
+
html[dir="rtl"] & { float: left; }
|
95
|
+
} @else if $dir == left {
|
96
|
+
html & { float: left; }
|
97
|
+
html[dir="ltr"] & { float: left; }
|
98
|
+
html[dir="rtl"] & { float: right; }
|
99
|
+
} @else {
|
100
|
+
html & html[dir="ltr"] &, html[dir="rtl"] & { float: $dir; }
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
@mixin menu-box {
|
105
|
+
background: $menu-background;
|
106
|
+
@include menu-shadow;
|
107
|
+
border: $menu-border;
|
108
|
+
}
|
109
|
+
|
110
|
+
@mixin menu-shadow {
|
111
|
+
@include box-shadow(0 0 ($fs-normal/4) rgba(0, 0, 0, 0.3));
|
112
|
+
}
|
113
|
+
|
114
|
+
@mixin menu {
|
115
|
+
@include menu-box;
|
116
|
+
&, li a {
|
117
|
+
font-weight: normal;
|
118
|
+
color: $text-color;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
@mixin legend-label {
|
123
|
+
&, * {
|
124
|
+
color: $neutral-color;
|
125
|
+
text-transform: uppercase;
|
126
|
+
font-size: $fs-small;
|
127
|
+
line-height: $lh-small;
|
128
|
+
font-weight: bold;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
@import "compass/reset";
|
2
|
+
|
3
|
+
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video, input, textarea, select, options, button {
|
4
|
+
margin: 0;
|
5
|
+
padding: 0;
|
6
|
+
font-family: $base-font-family;
|
7
|
+
vertical-align: middle;
|
8
|
+
font-size: $fs-normal;
|
9
|
+
line-height: $lh-normal;
|
10
|
+
color: $text-color;
|
11
|
+
}
|
12
|
+
|
13
|
+
html {
|
14
|
+
&, * {
|
15
|
+
@include text-align(left);
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
mark {
|
20
|
+
background-color: $highlight-color;
|
21
|
+
}
|
22
|
+
|
23
|
+
td, th, a, p, input, textarea, select, div {
|
24
|
+
font-size: $fs-normal;
|
25
|
+
}
|
26
|
+
small, sup, sub {
|
27
|
+
font-size: $fs-small;
|
28
|
+
}
|
29
|
+
a:link,
|
30
|
+
a:visited,
|
31
|
+
a:focus {
|
32
|
+
&, * {
|
33
|
+
color: $active-link-color;
|
34
|
+
text-decoration: none;
|
35
|
+
}
|
36
|
+
.label {
|
37
|
+
color: $base-font-reversed-color;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
/*
|
42
|
+
Other input types are: color, date, datetime, datetime-local, email, month,
|
43
|
+
number, range, search, tel, time, url, week, button, checkbox, color, date,
|
44
|
+
datetime, datetime-local, email, file, hidden, image, month, number, password,
|
45
|
+
radio, range, reset, search, submit, tel, text, time, url, week and file
|
46
|
+
*/
|
47
|
+
|
48
|
+
input[type="color"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="email"], input[type="image"], input[type="month"], input[type="number"], input[type="password"], input[type="range"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"], input[type="search"], textarea, select {
|
49
|
+
border: $menu-border;
|
50
|
+
padding: round($fs-normal * 0.2);
|
51
|
+
@include box-sizing(content-box);
|
52
|
+
@include border-radius($default-border-radius);
|
53
|
+
background: #FFF; //$desktop-background;
|
54
|
+
font-size: $fs-normal;
|
55
|
+
line-height: $lh-normal;
|
56
|
+
height: $lh-normal;
|
57
|
+
vertical-align: middle;
|
58
|
+
// @include box-shadow(0 2px round($fs-normal/2) rgba(black, 0.1) inset, 0 0 round($fs-normal*0.6) rgba(white, 0.6));
|
59
|
+
// @include box-shadow(0 2px round($fs-normal/2) rgba(black, 0.1) inset);
|
60
|
+
@include box-shadow(0 0 0 rgba(black, 0.1));
|
61
|
+
@include transition(box-shadow 0.2s, border-color 0.2s);
|
62
|
+
&:focus {
|
63
|
+
// background: #FFF;
|
64
|
+
border-color: $base-color;
|
65
|
+
@include box-shadow(0 0 round($fs-normal*0.6) rgba($base-color, 0.6));
|
66
|
+
}
|
67
|
+
&:disabled, &[disabled] {
|
68
|
+
background: #EEE;
|
69
|
+
color: #777;
|
70
|
+
cursor: not-allowed;
|
71
|
+
}
|
72
|
+
}
|
73
|
+
input[type="number"] {
|
74
|
+
@include text-align(right);
|
75
|
+
}
|
76
|
+
input[type="date"], input[type="datetime"] {
|
77
|
+
@include text-align(center);
|
78
|
+
}
|
79
|
+
input[type="date"] {
|
80
|
+
width: 12ex;
|
81
|
+
}
|
82
|
+
input[type="datetime"] {
|
83
|
+
width: 20ex;
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
textarea {
|
88
|
+
min-height: 3em;
|
89
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
// Basic colors
|
2
|
+
$white: #FFFFFF !default;
|
3
|
+
$black: #000000 !default;
|
4
|
+
|
5
|
+
// Font sizes
|
6
|
+
$fs-ratio: 1.2 !default;
|
7
|
+
$fs-small: 11px !default;
|
8
|
+
$fs-normal: 13px !default;
|
9
|
+
|
10
|
+
// Line heights
|
11
|
+
$lh-ratio: 1.61803398875 !default;
|
12
|
+
$lh-small: round($lh-ratio * $fs-small);
|
13
|
+
$lh-normal: round($lh-ratio * $fs-normal);
|
14
|
+
|
15
|
+
// Colors
|
16
|
+
$base-color: #688ED8 !default;
|
17
|
+
$highlight-color: #FFEE80 !default;
|
18
|
+
$neutral-color: mix($black, $white, 45%) !default;
|
19
|
+
$active-color: $base-color !default;
|
20
|
+
$active-link-color: darken($base-color, 10%) !default;
|
21
|
+
$title-color: darken($base-color, 40%) !default;
|
22
|
+
$text-color: darken($base-color, 40%) !default;
|
23
|
+
$base-font-reversed-color: $white !default;
|
24
|
+
|
25
|
+
$hover-transparency: 0.92 !default;
|
26
|
+
$hover-mask: transparentize($neutral-color, $hover-transparency);
|
27
|
+
|
28
|
+
$neutral-background: change-color($neutral-color, $lightness: 94%) !default;
|
29
|
+
|
30
|
+
// Menu colors
|
31
|
+
$menu-background: mix($neutral-background, $white, 55%) !default;
|
32
|
+
$menu-border-color: mix($menu-background, $black, 90%);
|
33
|
+
$menu-border-width: floor($fs-normal / 10);
|
34
|
+
$menu-border: $menu-border-width solid $menu-border-color;
|
35
|
+
|
36
|
+
|
37
|
+
$default-border-radius: round($fs-normal * 0.2);
|
38
|
+
$default-gap: round($fs-normal * 0.55);
|
39
|
+
|
40
|
+
// Map
|
41
|
+
$map-button-size: round(2 * $fs-normal);
|
42
|
+
|
43
|
+
// Font families
|
44
|
+
$sans-font-family: 'Open Sans', 'Droid Sans', 'Liberation Sans', Helvetica, sans-serif !default;
|
45
|
+
$base-font-family: $sans-font-family !default;
|
46
|
+
|
47
|
+
@import "bootstrap/variables"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'foliage'
|
2
|
+
|
3
|
+
module FoliageHelper
|
4
|
+
# Example of how to use in HAML view:
|
5
|
+
#
|
6
|
+
# = foliage do |leaf|
|
7
|
+
# - leaf.serie :data, <data>
|
8
|
+
# - leaf.background "openstreetmap.hot"
|
9
|
+
# - leaf.background "openweather.precipitations"
|
10
|
+
# - leaf.background "openweather.heat"
|
11
|
+
# - leaf.choropleth :<property>, :data
|
12
|
+
# - leaf.control :fullscreen
|
13
|
+
# - leaf.control :layer_selector
|
14
|
+
# - leaf.control :background_selector
|
15
|
+
# - leaf.control :search
|
16
|
+
#
|
17
|
+
def foliage(options = {}, html_options = {})
|
18
|
+
theme_colors = ['#2f7ed8', '#0d233a', '#8bbc21', '#910000', '#1aadce', '#492970', '#f28f43', '#77a1e5', '#c42525', '#a6c96a']
|
19
|
+
leaf = Foliage::Leaf.new({ categories_colors: theme_colors }.merge(options))
|
20
|
+
yield leaf
|
21
|
+
content_tag(:div, nil, html_options.deep_merge(data: { leaf: leaf.to_json }))
|
22
|
+
end
|
23
|
+
end
|
data/lib/foliage.rb
ADDED
data/lib/foliage/leaf.rb
ADDED
@@ -0,0 +1,235 @@
|
|
1
|
+
module Foliage
|
2
|
+
class Leaf
|
3
|
+
def initialize(config = {})
|
4
|
+
@config = config
|
5
|
+
@categories_colors = @config.delete(:categories_colors)
|
6
|
+
@config[:backgrounds] = map_backgrounds
|
7
|
+
end
|
8
|
+
|
9
|
+
def map_backgrounds
|
10
|
+
[
|
11
|
+
{
|
12
|
+
name: 'OpenStreetMap Hot',
|
13
|
+
url: 'http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png',
|
14
|
+
referenceName: 'open_street_map.hot',
|
15
|
+
attribution: '© <a href=\'http://openstreetmap.org\'>OpenStreetMap</a> contributors, <a href=\'http://creativecommons.org/licenses/by-sa/2.0/\'>CC-BY-SA</a>, Tiles courtesy of <a href=\'http://hot.openstreetmap.org/\' target=\'_blank\'>Humanitarian OpenStreetMap Team</a>',
|
16
|
+
tms: false,
|
17
|
+
byDefault: false
|
18
|
+
},
|
19
|
+
{
|
20
|
+
name: 'Thunderforest Landscape',
|
21
|
+
url: 'https://{s}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png',
|
22
|
+
referenceName: 'thunderforest.landscape',
|
23
|
+
attribution:
|
24
|
+
'Maps © <a href=\'http://www.thunderforest.com\'>Thunderforest</a>, Data © <a href=\'http://www.openstreetmap.org/copyright\'>OpenStreetMap contributors</a>',
|
25
|
+
subdomains: 'abc',
|
26
|
+
tms: false,
|
27
|
+
byDefault: false
|
28
|
+
},
|
29
|
+
{
|
30
|
+
name: 'Stamen Watercolor',
|
31
|
+
url: 'http://{s}.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg',
|
32
|
+
referenceName: 'stamen.watercolor',
|
33
|
+
attribution: 'Map tiles by <a href=\'http://stamen.com\'>Stamen Design</a>, <a href=\'http://creativecommons.org/licenses/by/3.0\'>CC BY 3.0</a> — Map data © <a href=\'http://openstreetmap.org\'>OpenStreetMap</a> contributors, <a href=\'http://creativecommons.org/licenses/by-sa/2.0/\'>CC-BY-SA</a>',
|
34
|
+
subdomains: 'abcd',
|
35
|
+
minZoom: 3,
|
36
|
+
maxZoom: 15,
|
37
|
+
tms: false,
|
38
|
+
byDefault: true
|
39
|
+
},
|
40
|
+
{
|
41
|
+
name: 'Esri World imagery',
|
42
|
+
url: 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
|
43
|
+
referenceName: 'esri.world_imagery',
|
44
|
+
attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community',
|
45
|
+
tms: false,
|
46
|
+
byDefault: false
|
47
|
+
}
|
48
|
+
]
|
49
|
+
end
|
50
|
+
|
51
|
+
def background(layer, options = {})
|
52
|
+
# allow to add custom background
|
53
|
+
options[:name] = layer.name if layer.name?
|
54
|
+
options[:url] = layer.url if layer.url?
|
55
|
+
options[:by_default] = layer.by_default if layer.by_default?
|
56
|
+
@config[:backgrounds] ||= []
|
57
|
+
@config[:backgrounds] << options
|
58
|
+
end
|
59
|
+
|
60
|
+
def overlay(name, provider_name)
|
61
|
+
@config[:overlays] ||= []
|
62
|
+
@config[:overlays] << { name: name, provider_name: provider_name }
|
63
|
+
end
|
64
|
+
|
65
|
+
# def layer(name, list = {})
|
66
|
+
# @config[:layers] ||= []
|
67
|
+
# @config[:layers] << {name: name, list: list}
|
68
|
+
# end
|
69
|
+
|
70
|
+
def layer(name, serie, options = {})
|
71
|
+
options[:label] = name.to_s.humanize unless options[:label]
|
72
|
+
name = name.to_s.parameterize.tr('-', '_') unless name.is_a?(Symbol)
|
73
|
+
@config[:layers] ||= []
|
74
|
+
@config[:layers] << { reference: name.to_s.camelcase(:lower) }.merge(options.merge(name: name, serie: serie.to_s.camelcase(:lower)))
|
75
|
+
end
|
76
|
+
|
77
|
+
def simple(name, serie, options = {})
|
78
|
+
layer(name, serie, options.merge(type: :simple))
|
79
|
+
end
|
80
|
+
|
81
|
+
def choropleth(name, serie, options = {})
|
82
|
+
layer(name, serie, options.merge(type: :choropleth))
|
83
|
+
end
|
84
|
+
|
85
|
+
def bubbles(name, serie, options = {})
|
86
|
+
layer(name, serie, options.merge(type: :bubbles))
|
87
|
+
end
|
88
|
+
|
89
|
+
def heatmap(name, serie, options = {})
|
90
|
+
layer(name, serie, options.merge(type: :heatmap))
|
91
|
+
end
|
92
|
+
|
93
|
+
def band(name, serie, options = {})
|
94
|
+
layer(name, serie, options.merge(type: :band))
|
95
|
+
end
|
96
|
+
|
97
|
+
def categories(name, serie, options = {})
|
98
|
+
layer(name, serie, { colors: @categories_colors }.merge(options.merge(type: :categories)))
|
99
|
+
end
|
100
|
+
|
101
|
+
def paths(name, serie, options = {})
|
102
|
+
layer(name, serie, { colors: @categories_colors }.merge(options.merge(type: :paths)))
|
103
|
+
end
|
104
|
+
|
105
|
+
def path(name, serie, options = {})
|
106
|
+
layer(name, serie, { colors: @categories_colors }.merge(options.merge(type: :path)))
|
107
|
+
end
|
108
|
+
|
109
|
+
def points(name, serie, options = {})
|
110
|
+
layer(name, serie, { colors: @categories_colors }.merge(options.merge(type: :points)))
|
111
|
+
end
|
112
|
+
|
113
|
+
def point_group(name, serie, options = {})
|
114
|
+
layer(name, serie, options.merge(type: :point_group))
|
115
|
+
end
|
116
|
+
|
117
|
+
# def multi_points(name, serie, options = {})
|
118
|
+
# layer(name, serie, options.merge(type: :multi_points))
|
119
|
+
# end
|
120
|
+
|
121
|
+
# Add a serie of geo data
|
122
|
+
def serie(name, data)
|
123
|
+
raise StandardError, 'data must be an array. Got: ' + data.class.name unless data.is_a? Array
|
124
|
+
@config[:series] ||= {}.with_indifferent_access
|
125
|
+
@config[:series][name] = data.compact.collect do |item|
|
126
|
+
next unless item[:shape]
|
127
|
+
item
|
128
|
+
.merge(shape: item[:shape])
|
129
|
+
.merge(item[:popup] ? { popup: compile_leaf_popup(item[:popup], item) } : {})
|
130
|
+
end.compact
|
131
|
+
end
|
132
|
+
|
133
|
+
# Add a control
|
134
|
+
def control(name, options = true)
|
135
|
+
@config[:controls] ||= {}.with_indifferent_access
|
136
|
+
@config[:controls][name.to_s.camelize(:lower)] = options
|
137
|
+
end
|
138
|
+
|
139
|
+
def to_json
|
140
|
+
@config.deep_transform_keys do |key|
|
141
|
+
key.to_s.camelize(:lower)
|
142
|
+
end.to_json
|
143
|
+
end
|
144
|
+
|
145
|
+
protected
|
146
|
+
|
147
|
+
# Build a data structure for popup building
|
148
|
+
def compile_leaf_popup(object, item)
|
149
|
+
if object.is_a?(TrueClass)
|
150
|
+
hash = { header: item[:name] }
|
151
|
+
for key, value in item
|
152
|
+
unless [:header, :footer, :name, :shape].include?(key)
|
153
|
+
hash[key] = value.to_s
|
154
|
+
end
|
155
|
+
end
|
156
|
+
compile_leaf_popup(hash, item)
|
157
|
+
elsif object.is_a?(String)
|
158
|
+
return [{ type: :content, content: object }]
|
159
|
+
elsif object.is_a?(Hash)
|
160
|
+
blocks = []
|
161
|
+
if header = object[:header]
|
162
|
+
blocks << compile_block(header, :header, content: item[:name])
|
163
|
+
end
|
164
|
+
if content = object[:content]
|
165
|
+
if content.is_a? String
|
166
|
+
blocks << { type: :content, content: content }
|
167
|
+
elsif content.is_a? Array
|
168
|
+
for value in content
|
169
|
+
block = {}
|
170
|
+
if value.is_a? String
|
171
|
+
block[:content] = value
|
172
|
+
elsif value.is_a? Hash
|
173
|
+
block.update(value)
|
174
|
+
else
|
175
|
+
raise "Not implemented array block for #{object.class}"
|
176
|
+
end
|
177
|
+
if block[:label].is_a?(TrueClass)
|
178
|
+
block[:label] = "attributes.#{attribute}".t(default: ["labels.#{attribute}".to_sym, attribute.to_s.humanize])
|
179
|
+
elsif !block[:label]
|
180
|
+
block.delete(:label)
|
181
|
+
end
|
182
|
+
blocks << block.merge(type: :content)
|
183
|
+
end
|
184
|
+
elsif content.is_a? Hash
|
185
|
+
for attribute, value in content
|
186
|
+
block = {}
|
187
|
+
if value.is_a? String
|
188
|
+
block[:content] = value
|
189
|
+
elsif value.is_a? Hash
|
190
|
+
block.update(value)
|
191
|
+
elsif value.is_a? TrueClass
|
192
|
+
block[:value] = item[attribute].to_s
|
193
|
+
block[:label] = true
|
194
|
+
end
|
195
|
+
if block[:label].is_a?(TrueClass)
|
196
|
+
block[:label] = attribute.to_s.humanize
|
197
|
+
elsif !block[:label]
|
198
|
+
block.delete(:label)
|
199
|
+
end
|
200
|
+
blocks << block.merge(type: :content)
|
201
|
+
end
|
202
|
+
else
|
203
|
+
raise "Not implemented content for #{content.class}"
|
204
|
+
end
|
205
|
+
end
|
206
|
+
if footer = object[:footer]
|
207
|
+
blocks << compile_block(footer, :footer, content: item[:name])
|
208
|
+
end
|
209
|
+
return blocks
|
210
|
+
else
|
211
|
+
raise "Not implemented for #{object.class}"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def compile_block(*args)
|
216
|
+
options = args.extract_options!
|
217
|
+
info = args.shift
|
218
|
+
type = args.shift || options[:type]
|
219
|
+
if info.is_a? String
|
220
|
+
block = { type: type, content: info }
|
221
|
+
elsif info.is_a? TrueClass
|
222
|
+
if options[:content]
|
223
|
+
block = { type: type, content: options[:content] }
|
224
|
+
else
|
225
|
+
raise StandardError, 'Option :content must be given when info is a TrueClass'
|
226
|
+
end
|
227
|
+
elsif info.is_a? Hash
|
228
|
+
block = info.merge(type: type)
|
229
|
+
else
|
230
|
+
raise StandardError, "Not implemented #{type} for #{object.class}"
|
231
|
+
end
|
232
|
+
block
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|