geo_pattern 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +53 -28
- data/lib/geo_pattern.rb +4 -3
- data/lib/geo_pattern/pattern/base_pattern.rb +47 -0
- data/lib/geo_pattern/pattern/chevron_pattern.rb +45 -0
- data/lib/geo_pattern/pattern/concentric_circles_pattern.rb +47 -0
- data/lib/geo_pattern/pattern/diamond_pattern.rb +56 -0
- data/lib/geo_pattern/pattern/hexagon_pattern.rb +57 -0
- data/lib/geo_pattern/pattern/mosaic_squares_pattern.rb +76 -0
- data/lib/geo_pattern/pattern/nested_squares_pattern.rb +51 -0
- data/lib/geo_pattern/pattern/octagon_pattern.rb +35 -0
- data/lib/geo_pattern/pattern/overlapping_circles_pattern.rb +46 -0
- data/lib/geo_pattern/pattern/overlapping_rings_pattern.rb +46 -0
- data/lib/geo_pattern/pattern/pattern_helpers.rb +19 -0
- data/lib/geo_pattern/pattern/plaid_pattern.rb +49 -0
- data/lib/geo_pattern/pattern/plus_sign_pattern.rb +53 -0
- data/lib/geo_pattern/pattern/sine_wave_pattern.rb +36 -0
- data/lib/geo_pattern/pattern/square_pattern.rb +27 -0
- data/lib/geo_pattern/pattern/tessellation_pattern.rb +93 -0
- data/lib/geo_pattern/pattern/triangle_pattern.rb +51 -0
- data/lib/geo_pattern/pattern/xes_pattern.rb +58 -0
- data/lib/geo_pattern/pattern_generator.rb +105 -0
- data/lib/geo_pattern/svg.rb +4 -0
- data/lib/geo_pattern/version.rb +1 -1
- metadata +33 -23
- data/lib/geo_pattern/pattern.rb +0 -906
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6321ec629bed93b949fb0af35e1930beb4c4bc17
|
4
|
+
data.tar.gz: 83b4d012dbf6d98585d2204da0f5f539baab5dd6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a2f516f74c4485678517044c9e726ae83ff851a5d0e3c71882eb0379f860f3a0b04c71ba32a93af85cfc101c009f8787bbe303f8638e2492bb8cd8b589207ada
|
7
|
+
data.tar.gz: ef40eefa6ff0cde718bec5916ab93eab6c84b843d0eb324d24a10ae406317765befbe04cc9b798bb122c2f7f6b750e8a25f07e57736e357ad9f00f4611f98d23
|
data/README.md
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
+
[![](http://img.shields.io/gem/v/geo_pattern.svg?style=flat)](http://rubygems.org/gems/geo_pattern)
|
2
|
+
[![](http://img.shields.io/gem/dt/geo_pattern.svg?style=flat)](http://rubygems.org/gems/geo_pattern)
|
3
|
+
|
1
4
|
# GeoPattern
|
2
5
|
|
3
6
|
Generate beautiful tiling SVG patterns from a string. The string is converted into a SHA and a color and pattern are determined based on the values in the hash. The color is determined by shifting the hue and saturation from a default (or passed in) base color. One of 16 patterns is used (or you can specify one) and the sizing of the pattern elements is also determined by the hash values.
|
4
7
|
|
5
8
|
You can use the generated pattern as the `background-image` for a container. Using the `base64` representation of the pattern still results in SVG rendering, so it looks great on retina displays.
|
6
9
|
|
7
|
-
See the [GitHub Guides](http://guides.github.com) site
|
10
|
+
See the [GitHub Guides](http://guides.github.com) site and the [Explore section of GitHub](https://github.com/explore) are examples of this library in action. Brandon Mills has put together an awesome [live preview page](http://btmills.github.io/geopattern/geopattern.html) that's built on his Javascript port.
|
8
11
|
|
9
12
|
## Installation
|
10
13
|
|
@@ -24,93 +27,109 @@ Or install it yourself as:
|
|
24
27
|
|
25
28
|
Make a new pattern:
|
26
29
|
|
27
|
-
|
30
|
+
```ruby
|
31
|
+
pattern = GeoPattern.generate("Mastering Markdown")
|
32
|
+
```
|
28
33
|
|
29
34
|
To specify a base background color (with a hue and saturation that adjusts depending on the string):
|
30
35
|
|
31
|
-
|
36
|
+
```ruby
|
37
|
+
pattern = GeoPattern.generate("Mastering Markdown", {:base_color => "#fc0"})
|
38
|
+
```
|
32
39
|
|
33
40
|
To use a specific background color (w/o any hue or saturation adjustments):
|
34
41
|
|
35
|
-
|
42
|
+
```ruby
|
43
|
+
pattern = GeoPattern.generate("Mastering Markdown", {:color => "#fc0"})
|
44
|
+
```
|
36
45
|
|
37
46
|
To use a specific [pattern generator](#available-patterns):
|
38
47
|
|
39
|
-
|
48
|
+
```ruby
|
49
|
+
pattern = GeoPattern.generate("Mastering Markdown", {:generator => GeoPattern::SineWavePattern})
|
50
|
+
```
|
40
51
|
|
41
52
|
Get the SVG string:
|
42
53
|
|
43
|
-
|
44
|
-
|
54
|
+
```ruby
|
55
|
+
puts pattern.svg_string
|
56
|
+
# => <svg xmlns="http://www.w3.org/2000/svg" ...
|
57
|
+
```
|
45
58
|
|
46
59
|
Get the Base64 encoded string:
|
47
60
|
|
48
|
-
|
49
|
-
|
61
|
+
```ruby
|
62
|
+
puts pattern.base64_string
|
63
|
+
# => PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC...
|
64
|
+
```
|
50
65
|
|
51
66
|
You can then use this string to set the background:
|
52
67
|
|
53
|
-
|
68
|
+
```html
|
69
|
+
<div style="background-image: <%= pattern.uri_image %>"></div>
|
70
|
+
```
|
54
71
|
|
55
72
|
## Available patterns
|
56
73
|
|
57
|
-
|
74
|
+
*Note: As of version `1.3.0`, string references (e.g. `overlapping_circles`) are deprecated in favor of class references (e.g. `GeoPattern::OverlappingCirclesPattern`).*
|
75
|
+
|
76
|
+
### GeoPattern::OctagonPattern
|
58
77
|
|
59
78
|
![](http://jasonlong.github.io/geo_pattern/examples/octogons.png)
|
60
79
|
|
61
|
-
###
|
80
|
+
### GeoPattern::OverlappingCirclesPattern
|
62
81
|
|
63
82
|
![](http://jasonlong.github.io/geo_pattern/examples/overlapping_circles.png)
|
64
83
|
|
65
|
-
###
|
84
|
+
### GeoPattern::PlusSignPattern
|
66
85
|
|
67
86
|
![](http://jasonlong.github.io/geo_pattern/examples/plus_signs.png)
|
68
87
|
|
69
|
-
###
|
88
|
+
### GeoPattern::XesPattern
|
70
89
|
|
71
90
|
![](http://jasonlong.github.io/geo_pattern/examples/xes.png)
|
72
91
|
|
73
|
-
###
|
92
|
+
### GeoPattern::SineWavePattern
|
74
93
|
|
75
94
|
![](http://jasonlong.github.io/geo_pattern/examples/sine_waves.png)
|
76
95
|
|
77
|
-
###
|
96
|
+
### GeoPattern::HexagonPattern
|
78
97
|
|
79
98
|
![](http://jasonlong.github.io/geo_pattern/examples/hexagons.png)
|
80
99
|
|
81
|
-
###
|
100
|
+
### GeoPattern::OverlappingCirclesPattern
|
82
101
|
|
83
102
|
![](http://jasonlong.github.io/geo_pattern/examples/overlapping_rings.png)
|
84
103
|
|
85
|
-
###
|
104
|
+
### GeoPattern::PlaidPattern
|
86
105
|
|
87
106
|
![](http://jasonlong.github.io/geo_pattern/examples/plaid.png)
|
88
107
|
|
89
|
-
###
|
108
|
+
### GeoPattern::TrianglePattern
|
90
109
|
|
91
110
|
![](http://jasonlong.github.io/geo_pattern/examples/triangles.png)
|
92
111
|
|
93
|
-
###
|
112
|
+
### GeoPattern::SquarePattern
|
94
113
|
|
95
114
|
![](http://jasonlong.github.io/geo_pattern/examples/squares.png)
|
96
115
|
|
97
|
-
###
|
116
|
+
### GeoPattern::NestedSquaresPattern
|
98
117
|
|
99
118
|
![](http://jasonlong.github.io/geo_pattern/examples/nested_squares.png)
|
100
119
|
|
101
|
-
###
|
120
|
+
### GeoPattern::MosaicSquaresPattern
|
102
121
|
|
103
122
|
![](http://jasonlong.github.io/geo_pattern/examples/mosaic_squares.png)
|
104
123
|
|
105
|
-
###
|
124
|
+
### GeoPattern::ConcentricCirclesPattern
|
106
125
|
|
107
126
|
![](http://jasonlong.github.io/geo_pattern/examples/concentric_circles.png)
|
108
127
|
|
109
|
-
###
|
128
|
+
### GeoPattern::DiamondPattern
|
110
129
|
|
111
130
|
![](http://jasonlong.github.io/geo_pattern/examples/diamonds.png)
|
112
131
|
|
113
|
-
###
|
132
|
+
### GeoPattern::TessellationPattern
|
114
133
|
|
115
134
|
![](http://jasonlong.github.io/geo_pattern/examples/tessellation.png)
|
116
135
|
|
@@ -125,11 +144,17 @@ You can then use this string to set the background:
|
|
125
144
|
|
126
145
|
## Ports
|
127
146
|
|
128
|
-
|
147
|
+
JavaScript port by Brandon Mills:
|
129
148
|
https://github.com/btmills/geopatterns-js
|
130
149
|
|
131
|
-
|
150
|
+
Python port by Bryan Veloso:
|
132
151
|
https://github.com/bryanveloso/geopatterns
|
133
152
|
|
134
|
-
|
153
|
+
PHP port by Anand Capur:
|
135
154
|
https://github.com/redeyeventures/geopattern-php
|
155
|
+
|
156
|
+
Go port by Pravendra Singh:
|
157
|
+
https://github.com/pravj/geo_pattern
|
158
|
+
|
159
|
+
CoffeeScript port by Aleks (muchweb):
|
160
|
+
https://github.com/muchweb/geo-pattern-coffee
|
data/lib/geo_pattern.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require "geo_pattern/version"
|
2
2
|
require "geo_pattern/svg"
|
3
|
-
require
|
3
|
+
require 'geo_pattern/pattern/pattern_helpers'
|
4
|
+
require "geo_pattern/pattern_generator"
|
4
5
|
|
5
6
|
module GeoPattern
|
6
|
-
def self.generate(string=Time.now
|
7
|
-
GeoPattern::
|
7
|
+
def self.generate(string=Time.now, opts={})
|
8
|
+
GeoPattern::PatternGenerator.new(string.to_s, opts)
|
8
9
|
end
|
9
10
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
class BasePattern < Struct.new(:svg, :hash)
|
3
|
+
FILL_COLOR_DARK = "#222"
|
4
|
+
FILL_COLOR_LIGHT = "#ddd"
|
5
|
+
STROKE_COLOR = "#000"
|
6
|
+
STROKE_OPACITY = 0.02
|
7
|
+
OPACITY_MIN = 0.02
|
8
|
+
OPACITY_MAX = 0.15
|
9
|
+
|
10
|
+
# Public: mutate the given `svg` object with a rendered pattern
|
11
|
+
#
|
12
|
+
# Note: this method _must_ be implemented by sub-
|
13
|
+
# classes.
|
14
|
+
#
|
15
|
+
# svg - the SVG container
|
16
|
+
#
|
17
|
+
# Returns a reference to the same `svg` object
|
18
|
+
# only this time with more patterns.
|
19
|
+
def render_to_svg
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
def hex_val(index, len)
|
24
|
+
PatternHelpers.hex_val(hash, index, len)
|
25
|
+
end
|
26
|
+
|
27
|
+
def fill_color(val)
|
28
|
+
(val.even?) ? FILL_COLOR_LIGHT : FILL_COLOR_DARK
|
29
|
+
end
|
30
|
+
|
31
|
+
def opacity(val)
|
32
|
+
map(val, 0, 15, OPACITY_MIN, OPACITY_MAX)
|
33
|
+
end
|
34
|
+
|
35
|
+
def map(value, v_min, v_max, d_min, d_max)
|
36
|
+
PatternHelpers.map(value, v_min, v_max, d_min, d_max)
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
def build_plus_shape(square_size)
|
41
|
+
[
|
42
|
+
"rect(#{square_size},0,#{square_size},#{square_size * 3})",
|
43
|
+
"rect(0, #{square_size},#{square_size * 3},#{square_size})"
|
44
|
+
]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
class ChevronPattern < BasePattern
|
3
|
+
def render_to_svg
|
4
|
+
chevron_width = map(hex_val(0, 1), 0, 15, 30, 80)
|
5
|
+
chevron_height = map(hex_val(0, 1), 0, 15, 30, 80)
|
6
|
+
chevron = build_chevron_shape(chevron_width, chevron_height)
|
7
|
+
|
8
|
+
svg.set_width(chevron_width * 6)
|
9
|
+
svg.set_height(chevron_height * 6 * 0.66)
|
10
|
+
|
11
|
+
i = 0
|
12
|
+
for y in 0..5
|
13
|
+
for x in 0..5
|
14
|
+
val = hex_val(i, 1)
|
15
|
+
opacity = opacity(val)
|
16
|
+
fill = fill_color(val)
|
17
|
+
|
18
|
+
styles = {
|
19
|
+
"stroke" => STROKE_COLOR,
|
20
|
+
"stroke-opacity" => STROKE_OPACITY,
|
21
|
+
"fill" => fill,
|
22
|
+
"fill-opacity" => opacity,
|
23
|
+
"stroke-width" => 1
|
24
|
+
}
|
25
|
+
|
26
|
+
svg.group(chevron, styles.merge({"transform" => "translate(#{x*chevron_width},#{y*chevron_height*0.66 - chevron_height/2})"}))
|
27
|
+
|
28
|
+
# Add an extra row at the end that matches the first row, for tiling.
|
29
|
+
if (y == 0)
|
30
|
+
svg.group(chevron, styles.merge({"transform" => "translate(#{x*chevron_width},#{6*chevron_height*0.66 - chevron_height/2})"}))
|
31
|
+
end
|
32
|
+
i += 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_chevron_shape(width, height)
|
38
|
+
e = height * 0.66
|
39
|
+
[
|
40
|
+
%Q{polyline("0,0,#{width/2},#{height-e},#{width/2},#{height},0,#{e},0,0")},
|
41
|
+
%Q{polyline("#{width/2},#{height-e},#{width},0,#{width},#{e},#{width/2},#{height},#{width/2},#{height-e}")}
|
42
|
+
]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
class ConcentricCirclesPattern < BasePattern
|
3
|
+
def render_to_svg
|
4
|
+
scale = hex_val(0, 1)
|
5
|
+
ring_size = map(scale, 0, 15, 10, 60)
|
6
|
+
stroke_width = ring_size / 5
|
7
|
+
|
8
|
+
svg.set_width((ring_size + stroke_width) * 6)
|
9
|
+
svg.set_height((ring_size + stroke_width) * 6)
|
10
|
+
|
11
|
+
i = 0
|
12
|
+
for y in 0..5
|
13
|
+
for x in 0..5
|
14
|
+
val = hex_val(i, 1)
|
15
|
+
opacity = opacity(val)
|
16
|
+
fill = fill_color(val)
|
17
|
+
|
18
|
+
svg.circle(
|
19
|
+
x*ring_size + x*stroke_width + (ring_size + stroke_width)/2,
|
20
|
+
y*ring_size + y*stroke_width + (ring_size + stroke_width)/2,
|
21
|
+
ring_size/2, {
|
22
|
+
"fill" => "none",
|
23
|
+
"stroke" => fill,
|
24
|
+
"style" => {
|
25
|
+
"opacity" => opacity,
|
26
|
+
"stroke-width" => "#{stroke_width}px"
|
27
|
+
}
|
28
|
+
})
|
29
|
+
|
30
|
+
val = hex_val(39-i, 1)
|
31
|
+
opacity = opacity(val)
|
32
|
+
fill = fill_color(val)
|
33
|
+
|
34
|
+
svg.circle(
|
35
|
+
x*ring_size + x*stroke_width + (ring_size + stroke_width)/2,
|
36
|
+
y*ring_size + y*stroke_width + (ring_size + stroke_width)/2,
|
37
|
+
ring_size/4, {
|
38
|
+
"fill" => fill,
|
39
|
+
"fill-opacity" => opacity
|
40
|
+
})
|
41
|
+
|
42
|
+
i += 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
class DiamondPattern < BasePattern
|
3
|
+
def render_to_svg
|
4
|
+
diamond_width = map(hex_val(0, 1), 0, 15, 10, 50)
|
5
|
+
diamond_height = map(hex_val(1, 1), 0, 15, 10, 50)
|
6
|
+
diamond = build_diamond_shape(diamond_width, diamond_height)
|
7
|
+
|
8
|
+
svg.set_width(diamond_width * 6)
|
9
|
+
svg.set_height(diamond_height * 3)
|
10
|
+
|
11
|
+
i = 0
|
12
|
+
for y in 0..5
|
13
|
+
for x in 0..5
|
14
|
+
val = hex_val(i, 1)
|
15
|
+
opacity = opacity(val)
|
16
|
+
fill = fill_color(val)
|
17
|
+
|
18
|
+
styles = {
|
19
|
+
"fill" => fill,
|
20
|
+
"fill-opacity" => opacity,
|
21
|
+
"stroke" => STROKE_COLOR,
|
22
|
+
"stroke-opacity" => STROKE_OPACITY
|
23
|
+
}
|
24
|
+
|
25
|
+
dx = (y % 2 == 0) ? 0 : diamond_width / 2
|
26
|
+
|
27
|
+
svg.polyline(diamond, styles.merge({
|
28
|
+
"transform" => "translate(#{x*diamond_width - diamond_width/2 + dx}, #{diamond_height/2*y - diamond_height/2})"}))
|
29
|
+
|
30
|
+
# Add an extra one at top-right, for tiling.
|
31
|
+
if (x == 0)
|
32
|
+
svg.polyline(diamond, styles.merge({
|
33
|
+
"transform" => "translate(#{6*diamond_width - diamond_width/2 + dx}, #{diamond_height/2*y - diamond_height/2})"}))
|
34
|
+
end
|
35
|
+
|
36
|
+
# Add an extra row at the end that matches the first row, for tiling.
|
37
|
+
if (y == 0)
|
38
|
+
svg.polyline(diamond, styles.merge({
|
39
|
+
"transform" => "translate(#{x*diamond_width - diamond_width/2 + dx}, #{diamond_height/2*6 - diamond_height/2})"}))
|
40
|
+
end
|
41
|
+
|
42
|
+
# Add an extra one at bottom-right, for tiling.
|
43
|
+
if (x == 0 and y == 0)
|
44
|
+
svg.polyline(diamond, styles.merge({
|
45
|
+
"transform" => "translate(#{6*diamond_width - diamond_width/2 + dx}, #{diamond_height/2*6 - diamond_height/2})"}))
|
46
|
+
end
|
47
|
+
i += 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def build_diamond_shape(width, height)
|
53
|
+
"#{width/2}, 0, #{width}, #{height/2}, #{width/2}, #{height}, 0, #{height/2}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
class HexagonPattern < BasePattern
|
3
|
+
def render_to_svg
|
4
|
+
scale = hex_val(0, 1)
|
5
|
+
side_length = map(scale, 0, 15, 8, 60)
|
6
|
+
hex_height = side_length * Math.sqrt(3)
|
7
|
+
hex_width = side_length * 2
|
8
|
+
hex = build_hexagon_shape(side_length)
|
9
|
+
|
10
|
+
svg.set_width((hex_width * 3) + (side_length * 3))
|
11
|
+
svg.set_height(hex_height * 6)
|
12
|
+
|
13
|
+
i = 0
|
14
|
+
for y in 0..5
|
15
|
+
for x in 0..5
|
16
|
+
val = hex_val(i, 1)
|
17
|
+
dy = x % 2 == 0 ? y*hex_height : y*hex_height + hex_height/2
|
18
|
+
opacity = opacity(val)
|
19
|
+
fill = fill_color(val)
|
20
|
+
|
21
|
+
styles = {
|
22
|
+
"fill" => fill,
|
23
|
+
"fill-opacity" => opacity,
|
24
|
+
"stroke" => STROKE_COLOR,
|
25
|
+
"stroke-opacity" => STROKE_OPACITY
|
26
|
+
}
|
27
|
+
|
28
|
+
svg.polyline(hex, styles.merge({"transform" => "translate(#{x*side_length*1.5 - hex_width/2}, #{dy - hex_height/2})"}))
|
29
|
+
|
30
|
+
# Add an extra one at top-right, for tiling.
|
31
|
+
if (x == 0)
|
32
|
+
svg.polyline(hex, styles.merge({"transform" => "translate(#{6*side_length*1.5 - hex_width/2}, #{dy - hex_height/2})"}))
|
33
|
+
end
|
34
|
+
|
35
|
+
# Add an extra row at the end that matches the first row, for tiling.
|
36
|
+
if (y == 0)
|
37
|
+
dy = x % 2 == 0 ? 6*hex_height : 6*hex_height + hex_height/2;
|
38
|
+
svg.polyline(hex, styles.merge({"transform" => "translate(#{x*side_length*1.5 - hex_width/2}, #{dy - hex_height/2})"}))
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add an extra one at bottom-right, for tiling.
|
42
|
+
if (x == 0 && y == 0)
|
43
|
+
svg.polyline(hex, styles.merge({"transform" => "translate(#{6*side_length*1.5 - hex_width/2}, #{5*hex_height + hex_height/2})"}))
|
44
|
+
end
|
45
|
+
i += 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_hexagon_shape(sideLength)
|
51
|
+
c = sideLength
|
52
|
+
a = c/2
|
53
|
+
b = Math.sin(60 * Math::PI / 180)*c
|
54
|
+
"0,#{b},#{a},0,#{a+c},0,#{2*c},#{b},#{a+c},#{2*b},#{a},#{2*b},0,#{b}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|