heatmap-builder 0.2.0 → 0.4.3
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -5
- data/CHANGELOG.md +70 -3
- data/Gemfile.lock +27 -24
- data/README.md +105 -135
- data/bin/generate_examples +42 -99
- data/examples/calendar_blue_ocean.svg +1 -1
- data/examples/calendar_cell_borders.svg +1 -0
- data/examples/calendar_default.svg +1 -1
- data/examples/calendar_github_style.svg +1 -1
- data/examples/calendar_month_spacing_rounded.svg +1 -0
- data/examples/calendar_no_borders.svg +1 -0
- data/examples/calendar_purple_vibes.svg +1 -1
- data/examples/calendar_red_to_green.svg +1 -1
- data/examples/calendar_rounded_corners.svg +1 -1
- data/examples/calendar_rounded_corners_max_radius.svg +1 -1
- data/examples/calendar_sunday_start.svg +1 -1
- data/examples/calendar_warm_sunset.svg +1 -1
- data/examples/calendar_with_outside_cells.svg +1 -1
- data/heatmap-builder.gemspec +4 -4
- data/lib/heatmap-builder.rb +5 -31
- data/lib/heatmap_builder/calendar.rb +426 -0
- data/lib/heatmap_builder/color_helpers.rb +121 -141
- data/lib/heatmap_builder/svg_helpers.rb +11 -4
- data/lib/heatmap_builder/value_conversion.rb +9 -5
- data/lib/heatmap_builder/version.rb +1 -1
- metadata +13 -22
- data/examples/large_cells.svg +0 -1
- data/examples/linear_blue_ocean.svg +0 -1
- data/examples/linear_github_green.svg +0 -1
- data/examples/linear_neon_gradient.svg +0 -1
- data/examples/linear_purple_vibes.svg +0 -1
- data/examples/linear_red_to_green.svg +0 -1
- data/examples/linear_rounded_corners.svg +0 -1
- data/examples/linear_rounded_corners_max_radius.svg +0 -1
- data/examples/linear_warm_sunset.svg +0 -1
- data/examples/weekly_progress.svg +0 -1
- data/lib/heatmap_builder/builder.rb +0 -100
- data/lib/heatmap_builder/calendar_heatmap_builder.rb +0 -310
- data/lib/heatmap_builder/linear_heatmap_builder.rb +0 -74
|
@@ -1,170 +1,150 @@
|
|
|
1
1
|
module HeatmapBuilder
|
|
2
2
|
module ColorHelpers
|
|
3
|
-
|
|
3
|
+
class << self
|
|
4
|
+
def score_to_color(score, colors:)
|
|
5
|
+
return colors.first if score == 0
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
colors = generate_color_palette(colors[:from], colors[:to], colors[:steps])
|
|
7
|
+
max_color_index = colors.length - 1
|
|
8
|
+
color_index = 1 + (score - 1) % max_color_index
|
|
9
|
+
colors[color_index]
|
|
9
10
|
end
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
def adjust_lightness(hex_color, factor:)
|
|
13
|
+
rgb = hex_to_rgb(hex_color)
|
|
14
|
+
oklch = rgb_to_oklch(*rgb)
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
colors[color_index]
|
|
16
|
-
end
|
|
16
|
+
darker_oklch = [oklch[0] * factor, oklch[1], oklch[2]]
|
|
17
|
+
darker_rgb = oklch_to_rgb(*darker_oklch)
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
oklch = rgb_to_oklch(*rgb)
|
|
19
|
+
rgb_to_hex(*darker_rgb)
|
|
20
|
+
end
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
def make_color_inactive(hex_color)
|
|
23
|
+
rgb = hex_to_rgb(hex_color)
|
|
24
|
+
oklch = rgb_to_oklch(*rgb)
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
inactive_oklch = [
|
|
27
|
+
oklch[0] * 0.85, # Slightly reduce lightness
|
|
28
|
+
oklch[1] * 0.4, # Significantly reduce chroma (saturation)
|
|
29
|
+
oklch[2] # Keep hue unchanged
|
|
30
|
+
]
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
oklch = rgb_to_oklch(*rgb)
|
|
33
|
-
|
|
34
|
-
# Reduce chroma (saturation) to make it more muted
|
|
35
|
-
# Also slightly reduce lightness
|
|
36
|
-
inactive_oklch = [
|
|
37
|
-
oklch[0] * 0.85, # Slightly reduce lightness
|
|
38
|
-
oklch[1] * 0.4, # Significantly reduce chroma (saturation)
|
|
39
|
-
oklch[2] # Keep hue unchanged
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
inactive_rgb = oklch_to_rgb(*inactive_oklch)
|
|
43
|
-
rgb_to_hex(*inactive_rgb)
|
|
44
|
-
end
|
|
32
|
+
inactive_rgb = oklch_to_rgb(*inactive_oklch)
|
|
33
|
+
rgb_to_hex(*inactive_rgb)
|
|
34
|
+
end
|
|
45
35
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
g_linear = srgb_to_linear(g / 255.0)
|
|
50
|
-
b_linear = srgb_to_linear(b / 255.0)
|
|
51
|
-
|
|
52
|
-
# Linear RGB to OKLab using the Oklab transformation matrix
|
|
53
|
-
l = 0.4122214708 * r_linear + 0.5363325363 * g_linear + 0.0514459929 * b_linear
|
|
54
|
-
m = 0.2119034982 * r_linear + 0.6806995451 * g_linear + 0.1073969566 * b_linear
|
|
55
|
-
s = 0.0883024619 * r_linear + 0.2817188376 * g_linear + 0.6299787005 * b_linear
|
|
56
|
-
|
|
57
|
-
# Apply cube root
|
|
58
|
-
l_root = (l >= 0) ? l**(1.0 / 3) : -((-l)**(1.0 / 3))
|
|
59
|
-
m_root = (m >= 0) ? m**(1.0 / 3) : -((-m)**(1.0 / 3))
|
|
60
|
-
s_root = (s >= 0) ? s**(1.0 / 3) : -((-s)**(1.0 / 3))
|
|
61
|
-
|
|
62
|
-
# Convert to OKLab
|
|
63
|
-
ok_l = 0.2104542553 * l_root + 0.7936177850 * m_root - 0.0040720468 * s_root
|
|
64
|
-
ok_a = 1.9779984951 * l_root - 2.4285922050 * m_root + 0.4505937099 * s_root
|
|
65
|
-
ok_b = 0.0259040371 * l_root + 0.7827717662 * m_root - 0.8086757660 * s_root
|
|
66
|
-
|
|
67
|
-
# Convert OKLab to OKLCH
|
|
68
|
-
chroma = Math.sqrt(ok_a * ok_a + ok_b * ok_b)
|
|
69
|
-
hue = Math.atan2(ok_b, ok_a) * 180.0 / Math::PI
|
|
70
|
-
hue += 360 if hue < 0
|
|
71
|
-
|
|
72
|
-
[ok_l, chroma, hue]
|
|
73
|
-
end
|
|
36
|
+
def generate_color_palette(from_color, to_color, steps)
|
|
37
|
+
from_rgb = hex_to_rgb(from_color)
|
|
38
|
+
to_rgb = hex_to_rgb(to_color)
|
|
74
39
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
hue_rad = hue * Math::PI / 180.0
|
|
78
|
-
ok_a = chroma * Math.cos(hue_rad)
|
|
79
|
-
ok_b = chroma * Math.sin(hue_rad)
|
|
80
|
-
|
|
81
|
-
# OKLab to linear RGB
|
|
82
|
-
l_root = ok_l + 0.3963377774 * ok_a + 0.2158037573 * ok_b
|
|
83
|
-
m_root = ok_l - 0.1055613458 * ok_a - 0.0638541728 * ok_b
|
|
84
|
-
s_root = ok_l - 0.0894841775 * ok_a - 1.2914855480 * ok_b
|
|
85
|
-
|
|
86
|
-
# Cube the values
|
|
87
|
-
l = l_root * l_root * l_root
|
|
88
|
-
m = m_root * m_root * m_root
|
|
89
|
-
s = s_root * s_root * s_root
|
|
90
|
-
|
|
91
|
-
# Convert to linear RGB
|
|
92
|
-
r_linear = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s
|
|
93
|
-
g_linear = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s
|
|
94
|
-
b_linear = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
|
|
95
|
-
|
|
96
|
-
# Convert to sRGB
|
|
97
|
-
r = linear_to_srgb(r_linear)
|
|
98
|
-
g = linear_to_srgb(g_linear)
|
|
99
|
-
b = linear_to_srgb(b_linear)
|
|
100
|
-
|
|
101
|
-
# Clamp to 0-255 and convert to integers
|
|
102
|
-
r = (r * 255).clamp(0, 255).round
|
|
103
|
-
g = (g * 255).clamp(0, 255).round
|
|
104
|
-
b = (b * 255).clamp(0, 255).round
|
|
105
|
-
|
|
106
|
-
[r, g, b]
|
|
107
|
-
end
|
|
40
|
+
from_oklch = rgb_to_oklch(*from_rgb)
|
|
41
|
+
to_oklch = rgb_to_oklch(*to_rgb)
|
|
108
42
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
43
|
+
colors = []
|
|
44
|
+
(0...steps).each do |i|
|
|
45
|
+
ratio = i.to_f / (steps - 1)
|
|
46
|
+
interpolated_oklch = interpolate_oklch(from_oklch, to_oklch, ratio)
|
|
47
|
+
interpolated_rgb = oklch_to_rgb(*interpolated_oklch)
|
|
48
|
+
colors << rgb_to_hex(*interpolated_rgb)
|
|
49
|
+
end
|
|
112
50
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
51
|
+
colors
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def rgb_to_oklch(r, g, b)
|
|
57
|
+
r_linear = srgb_to_linear(r / 255.0)
|
|
58
|
+
g_linear = srgb_to_linear(g / 255.0)
|
|
59
|
+
b_linear = srgb_to_linear(b / 255.0)
|
|
60
|
+
|
|
61
|
+
l = 0.4122214708 * r_linear + 0.5363325363 * g_linear + 0.0514459929 * b_linear
|
|
62
|
+
m = 0.2119034982 * r_linear + 0.6806995451 * g_linear + 0.1073969566 * b_linear
|
|
63
|
+
s = 0.0883024619 * r_linear + 0.2817188376 * g_linear + 0.6299787005 * b_linear
|
|
64
|
+
|
|
65
|
+
l_root = (l >= 0) ? l**(1.0 / 3) : -((-l)**(1.0 / 3))
|
|
66
|
+
m_root = (m >= 0) ? m**(1.0 / 3) : -((-m)**(1.0 / 3))
|
|
67
|
+
s_root = (s >= 0) ? s**(1.0 / 3) : -((-s)**(1.0 / 3))
|
|
116
68
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
hue_diff = hue2 - hue1
|
|
69
|
+
ok_l = 0.2104542553 * l_root + 0.7936177850 * m_root - 0.0040720468 * s_root
|
|
70
|
+
ok_a = 1.9779984951 * l_root - 2.4285922050 * m_root + 0.4505937099 * s_root
|
|
71
|
+
ok_b = 0.0259040371 * l_root + 0.7827717662 * m_root - 0.8086757660 * s_root
|
|
121
72
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
73
|
+
chroma = Math.sqrt(ok_a * ok_a + ok_b * ok_b)
|
|
74
|
+
hue = Math.atan2(ok_b, ok_a) * 180.0 / Math::PI
|
|
75
|
+
hue += 360 if hue < 0
|
|
76
|
+
|
|
77
|
+
[ok_l, chroma, hue]
|
|
127
78
|
end
|
|
128
79
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
80
|
+
def oklch_to_rgb(ok_l, chroma, hue)
|
|
81
|
+
hue_rad = hue * Math::PI / 180.0
|
|
82
|
+
ok_a = chroma * Math.cos(hue_rad)
|
|
83
|
+
ok_b = chroma * Math.sin(hue_rad)
|
|
132
84
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
interpolated_hue # H (hue)
|
|
137
|
-
]
|
|
138
|
-
end
|
|
85
|
+
l_root = ok_l + 0.3963377774 * ok_a + 0.2158037573 * ok_b
|
|
86
|
+
m_root = ok_l - 0.1055613458 * ok_a - 0.0638541728 * ok_b
|
|
87
|
+
s_root = ok_l - 0.0894841775 * ok_a - 1.2914855480 * ok_b
|
|
139
88
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
g = hex[2..3].to_i(16)
|
|
144
|
-
b = hex[4..5].to_i(16)
|
|
145
|
-
[r, g, b]
|
|
146
|
-
end
|
|
89
|
+
l = l_root * l_root * l_root
|
|
90
|
+
m = m_root * m_root * m_root
|
|
91
|
+
s = s_root * s_root * s_root
|
|
147
92
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
93
|
+
r_linear = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s
|
|
94
|
+
g_linear = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s
|
|
95
|
+
b_linear = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
|
|
151
96
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
97
|
+
r = linear_to_srgb(r_linear)
|
|
98
|
+
g = linear_to_srgb(g_linear)
|
|
99
|
+
b = linear_to_srgb(b_linear)
|
|
155
100
|
|
|
156
|
-
|
|
157
|
-
|
|
101
|
+
r = (r * 255).clamp(0, 255).round
|
|
102
|
+
g = (g * 255).clamp(0, 255).round
|
|
103
|
+
b = (b * 255).clamp(0, 255).round
|
|
158
104
|
|
|
159
|
-
|
|
160
|
-
(0...steps).each do |i|
|
|
161
|
-
ratio = i.to_f / (steps - 1)
|
|
162
|
-
interpolated_oklch = interpolate_oklch(from_oklch, to_oklch, ratio)
|
|
163
|
-
interpolated_rgb = oklch_to_rgb(*interpolated_oklch)
|
|
164
|
-
colors << rgb_to_hex(*interpolated_rgb)
|
|
105
|
+
[r, g, b]
|
|
165
106
|
end
|
|
166
107
|
|
|
167
|
-
|
|
108
|
+
def srgb_to_linear(component)
|
|
109
|
+
(component <= 0.04045) ? component / 12.92 : ((component + 0.055) / 1.055)**2.4
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def linear_to_srgb(component)
|
|
113
|
+
(component <= 0.0031308) ? component * 12.92 : 1.055 * (component**(1.0 / 2.4)) - 0.055
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def interpolate_oklch(oklch1, oklch2, ratio)
|
|
117
|
+
hue1, hue2 = oklch1[2], oklch2[2]
|
|
118
|
+
hue_diff = hue2 - hue1
|
|
119
|
+
|
|
120
|
+
if hue_diff > 180
|
|
121
|
+
hue_diff -= 360
|
|
122
|
+
elsif hue_diff < -180
|
|
123
|
+
hue_diff += 360
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
interpolated_hue = hue1 + hue_diff * ratio
|
|
127
|
+
interpolated_hue += 360 if interpolated_hue < 0
|
|
128
|
+
interpolated_hue -= 360 if interpolated_hue >= 360
|
|
129
|
+
|
|
130
|
+
[
|
|
131
|
+
oklch1[0] + (oklch2[0] - oklch1[0]) * ratio,
|
|
132
|
+
oklch1[1] + (oklch2[1] - oklch1[1]) * ratio,
|
|
133
|
+
interpolated_hue
|
|
134
|
+
]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def hex_to_rgb(hex_color)
|
|
138
|
+
hex = hex_color.delete("#")
|
|
139
|
+
r = hex[0..1].to_i(16)
|
|
140
|
+
g = hex[2..3].to_i(16)
|
|
141
|
+
b = hex[4..5].to_i(16)
|
|
142
|
+
[r, g, b]
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def rgb_to_hex(r, g, b)
|
|
146
|
+
"#%02x%02x%02x" % [r, g, b]
|
|
147
|
+
end
|
|
168
148
|
end
|
|
169
149
|
end
|
|
170
150
|
end
|
|
@@ -4,7 +4,7 @@ module HeatmapBuilder
|
|
|
4
4
|
|
|
5
5
|
def svg_element(tag, attributes = {}, &block)
|
|
6
6
|
attr_string = attributes.map do |key, value|
|
|
7
|
-
"#{kebab_case(key)}=\"#{value}\""
|
|
7
|
+
"#{kebab_case(key)}=\"#{escape_xml(value.to_s)}\""
|
|
8
8
|
end.join(" ")
|
|
9
9
|
|
|
10
10
|
attr_string = " #{attr_string}" unless attr_string.empty?
|
|
@@ -35,7 +35,7 @@ module HeatmapBuilder
|
|
|
35
35
|
font_family: "Arial, sans-serif"
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
svg_element("text", {x: x, y: y}.merge(default_attrs).merge(attributes)) { content }
|
|
38
|
+
svg_element("text", {x: x, y: y}.merge(default_attrs).merge(attributes)) { escape_xml(content) }
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def svg_container(width:, height:, &block)
|
|
@@ -50,14 +50,21 @@ module HeatmapBuilder
|
|
|
50
50
|
key.to_s.tr("_", "-")
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def
|
|
53
|
+
def escape_xml(str)
|
|
54
|
+
str.gsub("&", "&").gsub("<", "<").gsub(">", ">").gsub('"', """)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def cell_border(x, y, color, cell_size:, border_width:, corner_radius:, border_lightness_factor: 0.9)
|
|
54
58
|
return "" unless border_width > 0
|
|
59
|
+
# A factor of 1 leaves the color unchanged, so the border matches the
|
|
60
|
+
# fill exactly and would be invisible. Skip drawing it entirely.
|
|
61
|
+
return "" if border_lightness_factor == 1
|
|
55
62
|
|
|
56
63
|
inset = border_width / 2.0
|
|
57
64
|
border_x = x + inset
|
|
58
65
|
border_y = y + inset
|
|
59
66
|
border_size = cell_size - border_width
|
|
60
|
-
border_color =
|
|
67
|
+
border_color = ColorHelpers.adjust_lightness(color, factor: border_lightness_factor)
|
|
61
68
|
border_radius = (corner_radius > 0) ? [corner_radius - inset, 0].max : 0
|
|
62
69
|
|
|
63
70
|
svg_rect(
|
|
@@ -32,11 +32,9 @@ module HeatmapBuilder
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def convert_value_to_score(value, **params)
|
|
35
|
-
value = value_min if value.nil?
|
|
36
|
-
|
|
37
35
|
if options[:value_to_score]
|
|
38
36
|
score = options[:value_to_score].call(
|
|
39
|
-
value: value,
|
|
37
|
+
value: value.nil? ? value_min : value,
|
|
40
38
|
min: value_min,
|
|
41
39
|
max: value_max,
|
|
42
40
|
max_score: color_count - 1,
|
|
@@ -50,14 +48,20 @@ module HeatmapBuilder
|
|
|
50
48
|
return score
|
|
51
49
|
end
|
|
52
50
|
|
|
51
|
+
# Score 0 is reserved for empty cells (zero or missing values). Any
|
|
52
|
+
# non-zero value maps into 1..max_score so even the smallest activity is
|
|
53
|
+
# visibly distinct from an empty day.
|
|
54
|
+
return 0 if value.nil? || value.zero?
|
|
55
|
+
|
|
56
|
+
max_score = color_count - 1
|
|
53
57
|
clamped_value = value.clamp(value_min, value_max)
|
|
54
58
|
|
|
55
59
|
if value_min == value_max
|
|
56
|
-
|
|
60
|
+
max_score
|
|
57
61
|
else
|
|
58
62
|
range = value_max - value_min
|
|
59
63
|
normalized = (clamped_value - value_min).to_f / range
|
|
60
|
-
(normalized * (
|
|
64
|
+
1 + (normalized * (max_score - 1)).round
|
|
61
65
|
end
|
|
62
66
|
end
|
|
63
67
|
end
|
metadata
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: heatmap-builder
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Musayev
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-06-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '2.0'
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '2.0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: '13.0'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - "
|
|
38
|
+
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '13.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: minitest
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
45
|
+
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '5.0'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - "
|
|
52
|
+
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '5.0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
@@ -102,8 +102,11 @@ files:
|
|
|
102
102
|
- bin/generate_examples
|
|
103
103
|
- bin/setup
|
|
104
104
|
- examples/calendar_blue_ocean.svg
|
|
105
|
+
- examples/calendar_cell_borders.svg
|
|
105
106
|
- examples/calendar_default.svg
|
|
106
107
|
- examples/calendar_github_style.svg
|
|
108
|
+
- examples/calendar_month_spacing_rounded.svg
|
|
109
|
+
- examples/calendar_no_borders.svg
|
|
107
110
|
- examples/calendar_purple_vibes.svg
|
|
108
111
|
- examples/calendar_red_to_green.svg
|
|
109
112
|
- examples/calendar_rounded_corners.svg
|
|
@@ -111,22 +114,10 @@ files:
|
|
|
111
114
|
- examples/calendar_sunday_start.svg
|
|
112
115
|
- examples/calendar_warm_sunset.svg
|
|
113
116
|
- examples/calendar_with_outside_cells.svg
|
|
114
|
-
- examples/large_cells.svg
|
|
115
|
-
- examples/linear_blue_ocean.svg
|
|
116
|
-
- examples/linear_github_green.svg
|
|
117
|
-
- examples/linear_neon_gradient.svg
|
|
118
|
-
- examples/linear_purple_vibes.svg
|
|
119
|
-
- examples/linear_red_to_green.svg
|
|
120
|
-
- examples/linear_rounded_corners.svg
|
|
121
|
-
- examples/linear_rounded_corners_max_radius.svg
|
|
122
|
-
- examples/linear_warm_sunset.svg
|
|
123
|
-
- examples/weekly_progress.svg
|
|
124
117
|
- heatmap-builder.gemspec
|
|
125
118
|
- lib/heatmap-builder.rb
|
|
126
|
-
- lib/heatmap_builder/
|
|
127
|
-
- lib/heatmap_builder/calendar_heatmap_builder.rb
|
|
119
|
+
- lib/heatmap_builder/calendar.rb
|
|
128
120
|
- lib/heatmap_builder/color_helpers.rb
|
|
129
|
-
- lib/heatmap_builder/linear_heatmap_builder.rb
|
|
130
121
|
- lib/heatmap_builder/svg_helpers.rb
|
|
131
122
|
- lib/heatmap_builder/value_conversion.rb
|
|
132
123
|
- lib/heatmap_builder/version.rb
|
|
@@ -146,7 +137,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
146
137
|
requirements:
|
|
147
138
|
- - ">="
|
|
148
139
|
- !ruby/object:Gem::Version
|
|
149
|
-
version: '3.
|
|
140
|
+
version: '3.3'
|
|
150
141
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
151
142
|
requirements:
|
|
152
143
|
- - ">="
|
data/examples/large_cells.svg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="251" height="35" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="35" height="35" fill="#9be9a8"/><rect x="0.5" y="0.5" width="34" height="34" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="17" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">1</text><rect x="36" y="0" width="35" height="35" fill="#40c463"/><rect x="36.5" y="0.5" width="34" height="34" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="53" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">2</text><rect x="72" y="0" width="35" height="35" fill="#30a14e"/><rect x="72.5" y="0.5" width="34" height="34" fill="none" stroke="#108d3b" stroke-width="1"/><text x="89" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">3</text><rect x="108" y="0" width="35" height="35" fill="#216e39"/><rect x="108.5" y="0.5" width="34" height="34" fill="none" stroke="#0d602c" stroke-width="1"/><text x="125" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">4</text><rect x="144" y="0" width="35" height="35" fill="#9be9a8"/><rect x="144.5" y="0.5" width="34" height="34" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="161" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">5</text><rect x="180" y="0" width="35" height="35" fill="#40c463"/><rect x="180.5" y="0.5" width="34" height="34" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="197" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">6</text><rect x="216" y="0" width="35" height="35" fill="#30a14e"/><rect x="216.5" y="0.5" width="34" height="34" fill="none" stroke="#108d3b" stroke-width="1"/><text x="233" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">7</text></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#f0f9ff"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#d0d9df" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#bae6fd"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#9dc9df" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#7dd3fc"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#62b8e0" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#38bdf8"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#03a5df" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#0ea5e9"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#008fd2" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#bae6fd"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#9dc9df" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#7dd3fc"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#62b8e0" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#38bdf8"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#03a5df" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#0ea5e9"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#008fd2" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#bae6fd"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#9dc9df" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#ebedf0"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#ccced1" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#9be9a8"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#40c463"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#30a14e"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#108d3b" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#216e39"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#0d602c" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#9be9a8"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#40c463"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#30a14e"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#108d3b" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#216e39"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#0d602c" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#9be9a8"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#00ffff"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#00e0e1" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#00dbff"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#00c0e3" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#96a6ff"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#808fe5" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#db69ff"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#c351e6" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#ff1493"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#e6007f" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#00dbff"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#00c0e3" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#96a6ff"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#808fe5" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#db69ff"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#c351e6" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#ff1493"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#e6007f" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#00dbff"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#00c0e3" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#f3e8ff"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#d4c9e0" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#d8b4fe"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#bd9ae2" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#c084fc"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#a96de3" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#a855f7"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#953fe1" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#9333ea"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#8316d7" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#d8b4fe"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#bd9ae2" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#c084fc"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#a96de3" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#a855f7"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#953fe1" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#9333ea"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#8316d7" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#d8b4fe"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#bd9ae2" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#f5f5f5"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#d5d5d5" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#ff9999"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#e48081" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#f7ad6a"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#dc9450" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#d2c768"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#b8ad4d" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#99dd99"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#7fc27f" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#ff9999"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#e48081" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#f7ad6a"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#dc9450" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#d2c768"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#b8ad4d" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#99dd99"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#7fc27f" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#ff9999"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#e48081" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" rx="2" fill="#ebedf0"/><rect x="0.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#ccced1" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" rx="2" fill="#9be9a8"/><rect x="19.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" rx="2" fill="#40c463"/><rect x="38.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" rx="2" fill="#30a14e"/><rect x="57.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#108d3b" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" rx="2" fill="#216e39"/><rect x="76.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#0d602c" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" rx="2" fill="#9be9a8"/><rect x="95.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" rx="2" fill="#40c463"/><rect x="114.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" rx="2" fill="#30a14e"/><rect x="133.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#108d3b" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" rx="2" fill="#216e39"/><rect x="152.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#0d602c" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" rx="2" fill="#9be9a8"/><rect x="171.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" rx="9" fill="#ebedf0"/><rect x="0.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#ccced1" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" rx="9" fill="#9be9a8"/><rect x="19.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" rx="9" fill="#40c463"/><rect x="38.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" rx="9" fill="#30a14e"/><rect x="57.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#108d3b" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" rx="9" fill="#216e39"/><rect x="76.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#0d602c" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" rx="9" fill="#9be9a8"/><rect x="95.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" rx="9" fill="#40c463"/><rect x="114.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" rx="9" fill="#30a14e"/><rect x="133.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#108d3b" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" rx="9" fill="#216e39"/><rect x="152.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#0d602c" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" rx="9" fill="#9be9a8"/><rect x="171.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#fef3e2"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#ded3c3" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#fed7aa"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#e0ba8e" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#fdba74"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#e19f59" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#fb923c"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#e17a1a" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#f97316"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#e05c00" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#fed7aa"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#e0ba8e" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#fdba74"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#e19f59" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#fb923c"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#e17a1a" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#f97316"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#e05c00" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#fed7aa"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#e0ba8e" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg width="132" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#ebedf0"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#ccced1" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#9be9a8"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#30a14e"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#108d3b" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="57" y="0" width="18" height="18" fill="#40c463"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="76" y="0" width="18" height="18" fill="#216e39"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#0d602c" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#9be9a8"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="114" y="0" width="18" height="18" fill="#ebedf0"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#ccced1" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text></svg>
|