victor 0.3.4 → 0.5.0
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/README.md +28 -482
- data/lib/victor/attributes.rb +5 -7
- data/lib/victor/component.rb +61 -0
- data/lib/victor/css.rb +9 -9
- data/lib/victor/dsl.rb +1 -1
- data/lib/victor/marshaling.rb +33 -0
- data/lib/victor/svg.rb +7 -3
- data/lib/victor/svg_base.rb +21 -18
- data/lib/victor/templates/default.svg +2 -9
- data/lib/victor/templates/minimal.svg +1 -1
- data/lib/victor/version.rb +2 -2
- data/lib/victor.rb +9 -6
- metadata +15 -9
- data/lib/victor/templates/html.svg +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86eac1cab671c40d60409cf11e0e06800add519f2a11e80f33adbb8a516b7906
|
4
|
+
data.tar.gz: ff574def00c021acf82c0071ce6d9467576a74e0651663ecd7291ca2e5884ea7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fa1657d2e98c4bf98468f9f1e9a69a07c0c049eac6033d0bb3d2bbe603627cb448034923f94e6aef31db755ca66916a484ad521c86534c32274ef764a31ed79
|
7
|
+
data.tar.gz: 1a0662ce919d6abed8bea839c4fef03f7314960dbeaa5602b1627b44e4f69082e3ce933de57170c17973a58ab8f61ee7bb214796c99e641b35a3dec59a54d945
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
<div align='center'>
|
2
|
+
<img src='assets/logo.svg' width=500>
|
2
3
|
|
3
4
|
# Victor - Ruby SVG Image Builder
|
4
5
|
|
@@ -6,32 +7,14 @@
|
|
6
7
|
[](https://github.com/DannyBen/victor/actions?query=workflow%3ATest)
|
7
8
|
[](https://codeclimate.com/github/DannyBen/victor/maintainability)
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
Victor is a direct Ruby-to-SVG builder. All method calls are converted
|
12
|
-
directly to SVG elements.
|
10
|
+
## [victor.dannyb.co](https://victor.dannyb.co)
|
13
11
|
|
14
|
-
|
12
|
+
</div>
|
15
13
|
|
16
14
|
---
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
* [Install](#install)
|
21
|
-
* [Examples](#examples)
|
22
|
-
* [Usage](#usage)
|
23
|
-
* [Features](#features)
|
24
|
-
* [Composite SVG](#composite-svg)
|
25
|
-
* [Saving the Output](#saving-the-output)
|
26
|
-
* [SVG Templates](#svg-templates)
|
27
|
-
* [CSS](#css)
|
28
|
-
* [Tagless Elements](#tagless-elements)
|
29
|
-
* [XML Encoding](#xml-encoding)
|
30
|
-
* [XML Newlines](#xml-newlines)
|
31
|
-
* [DSL Syntax](#dsl-syntax)
|
32
|
-
* [Using with Rails](#using-with-rails)
|
33
|
-
* [Related Projects](#related-projects)
|
34
|
-
* [Contributing / Support](#contributing--support)
|
16
|
+
**Victor** is a lightweight, zero-dependencies Ruby library that lets you build
|
17
|
+
SVG images using Ruby code.
|
35
18
|
|
36
19
|
---
|
37
20
|
|
@@ -41,483 +24,46 @@ directly to SVG elements.
|
|
41
24
|
$ gem install victor
|
42
25
|
```
|
43
26
|
|
44
|
-
|
45
|
-
|
46
|
-
```ruby
|
47
|
-
gem 'victor'
|
48
|
-
```
|
49
|
-
|
50
|
-
## Examples
|
51
|
-
|
52
|
-
```ruby
|
53
|
-
require 'victor'
|
54
|
-
|
55
|
-
svg = Victor::SVG.new width: 140, height: 100, style: { background: '#ddd' }
|
56
|
-
|
57
|
-
svg.build do
|
58
|
-
rect x: 10, y: 10, width: 120, height: 80, rx: 10, fill: '#666'
|
59
|
-
|
60
|
-
circle cx: 50, cy: 50, r: 30, fill: 'yellow'
|
61
|
-
circle cx: 58, cy: 32, r: 4, fill: 'black'
|
62
|
-
polygon points: %w[45,50 80,30 80,70], fill: '#666'
|
63
|
-
|
64
|
-
3.times do |i|
|
65
|
-
x = 80 + i*18
|
66
|
-
circle cx: x, cy: 50, r: 4, fill: 'yellow'
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
svg.save 'pacman'
|
71
|
-
```
|
72
|
-
|
73
|
-
Output:
|
74
|
-
|
75
|
-
[](https://github.com/DannyBen/victor/blob/master/examples/10_pacman.rb)
|
76
|
-
|
77
|
-
|
78
|
-
See the [examples] folder for several ruby scripts and their SVG output.
|
79
|
-
|
80
|
-
|
81
|
-
## Usage
|
82
|
-
|
83
|
-
Initialize your SVG image:
|
84
|
-
|
85
|
-
```ruby
|
86
|
-
require 'victor'
|
87
|
-
svg = Victor::SVG.new
|
88
|
-
```
|
89
|
-
|
90
|
-
Any option you provide to `SVG.new` will be added as an attribute to the
|
91
|
-
main `<svg>` element. By default, `height` and `width` are set to 100%.
|
92
|
-
|
93
|
-
```ruby
|
94
|
-
svg = Victor::SVG.new width: '100%', height: '100%'
|
95
|
-
# same as just Victor::SVG.new
|
96
|
-
|
97
|
-
svg = Victor::SVG.new width: '100%', height: '100%', viewBox: "0 0 200 100"
|
98
|
-
```
|
99
|
-
|
100
|
-
As an alternative, you can set the root SVG attributes using the `setup` method:
|
101
|
-
|
102
|
-
```ruby
|
103
|
-
require 'victor'
|
104
|
-
svg = Victor::SVG.new
|
105
|
-
svg.setup width: 200, height: 150
|
106
|
-
```
|
107
|
-
|
108
|
-
Victor uses a single method (`element`) to generate all SVG elements:
|
109
|
-
|
110
|
-
```ruby
|
111
|
-
svg.element :rect, x: 2, y: 2, width: 200, height: 200
|
112
|
-
# => <rect x="2" y="2" width="200" height="200"/>
|
113
|
-
```
|
114
|
-
|
115
|
-
But you can omit it. Calls to any other method, will be delegated to the
|
116
|
-
`element` method, so normal usage looks more like this:
|
117
|
-
|
118
|
-
```ruby
|
119
|
-
svg.rect x: 2, y: 2, width: 200, height: 200
|
120
|
-
# => <rect x="2" y="2" width="200" height="200"/>
|
121
|
-
```
|
122
|
-
|
123
|
-
In other words, these are the same:
|
124
|
-
|
125
|
-
```ruby
|
126
|
-
svg.element :anything, option: 'value'
|
127
|
-
svg.anything option: 'value'
|
128
|
-
```
|
129
|
-
|
130
|
-
You can use the `build` method, to generate the SVG with a block
|
131
|
-
|
132
|
-
```ruby
|
133
|
-
svg.build do
|
134
|
-
rect x: 0, y: 0, width: 100, height: 100, fill: '#ccc'
|
135
|
-
rect x: 20, y: 20, width: 60, height: 60, fill: '#f99'
|
136
|
-
end
|
137
|
-
```
|
138
|
-
|
139
|
-
If the value of an attribute is a hash, it will be converted to a
|
140
|
-
style-compatible string:
|
141
|
-
|
142
|
-
```ruby
|
143
|
-
svg.rect x: 0, y: 0, width: 100, height: 100, style: { stroke: '#ccc', fill: 'red' }
|
144
|
-
# => <rect x=0 y=0 width=100 height=100 style="stroke:#ccc; fill:red"/>
|
145
|
-
```
|
146
|
-
|
147
|
-
If the value of an attribute is an array, it will be converted to a
|
148
|
-
space delimited string:
|
149
|
-
|
150
|
-
```ruby
|
151
|
-
svg.path d: ['M', 150, 0, 'L', 75, 200, 'L', 225, 200, 'Z']
|
152
|
-
# => <path d="M 150 0 L 75 200 L 225 200 Z"/>
|
153
|
-
```
|
154
|
-
|
155
|
-
For SVG elements that have an inner content - such as text - simply pass it as
|
156
|
-
the first argument:
|
157
|
-
|
158
|
-
```ruby
|
159
|
-
svg.text "Victor", x: 40, y: 50
|
160
|
-
# => <text x="40" y="50">Victor</text>
|
161
|
-
```
|
162
|
-
|
163
|
-
You can also nest elements with blocks:
|
164
|
-
|
165
|
-
```ruby
|
166
|
-
svg.build do
|
167
|
-
g font_size: 30, font_family: 'arial', fill: 'white' do
|
168
|
-
text "Scalable Victor Graphics", x: 40, y: 50
|
169
|
-
end
|
170
|
-
end
|
171
|
-
# => <g font-size="30" font-family="arial" fill="white">
|
172
|
-
# <text x="40" y="50">Scalable Victor Graphics</text>
|
173
|
-
# </g>
|
174
|
-
```
|
175
|
-
|
176
|
-
Underscores in attribute names are converted to dashes:
|
177
|
-
|
178
|
-
```ruby
|
179
|
-
svg.text "Victor", x: 40, y: 50, font_family: 'arial', font_weight: 'bold', font_size: 40
|
180
|
-
# => <text x="40" y="50" font-family="arial" font-weight="bold" font-size="40">
|
181
|
-
# Victor
|
182
|
-
# </text>
|
183
|
-
```
|
184
|
-
|
185
|
-
## Features
|
186
|
-
|
187
|
-
### Composite SVG
|
188
|
-
|
189
|
-
Victor also supports the ability to combine several smaller SVG objects into
|
190
|
-
one using the `<<` operator or the `#append` method.
|
191
|
-
|
192
|
-
This operator expects to receive any object that responds to `#to_s` (can be another `SVG` object).
|
193
|
-
|
194
|
-
```ruby
|
195
|
-
require 'victor'
|
196
|
-
include Victor
|
197
|
-
|
198
|
-
# Create a reusable SVG object
|
199
|
-
frame = SVG.new
|
200
|
-
frame.rect x: 0, y: 0, width: 100, height: 100, fill: '#336'
|
201
|
-
frame.rect x: 10, y: 10, width: 80, height: 80, fill: '#fff'
|
202
|
-
|
203
|
-
# ... and another
|
204
|
-
troll = SVG.new
|
205
|
-
troll.circle cx: 50, cy: 60, r: 24, fill: 'yellow'
|
206
|
-
troll.polygon points: %w[24,50 50,14 76,54], fill: 'red'
|
207
|
-
|
208
|
-
# Combine objects into a single image
|
209
|
-
svg = SVG.new viewBox: '0 0 100 100'
|
210
|
-
svg << frame
|
211
|
-
svg << troll
|
212
|
-
|
213
|
-
# ... and save it
|
214
|
-
svg.save 'framed-troll'
|
215
|
-
```
|
216
|
-
|
217
|
-
Output:
|
218
|
-
|
219
|
-
[](https://cdn.rawgit.com/DannyBen/victor/master/examples/14_composite_svg.svg)
|
220
|
-
|
221
|
-
These two calls are identical:
|
27
|
+
## Example
|
222
28
|
|
223
|
-
|
224
|
-
svg << other
|
225
|
-
svg.append other
|
226
|
-
```
|
29
|
+
<table><tr><td width="250">
|
227
30
|
|
228
|
-
|
31
|
+
<img src='assets/ghost.svg' width=250>
|
229
32
|
|
230
|
-
|
231
|
-
troll = SVG.new do
|
232
|
-
circle cx: 50, cy: 60, r: 24, fill: 'yellow'
|
233
|
-
end
|
234
|
-
```
|
235
|
-
|
236
|
-
Which is the same as:
|
33
|
+
</td><td>
|
237
34
|
|
238
35
|
```ruby
|
239
|
-
|
240
|
-
troll.build do
|
241
|
-
circle cx: 50, cy: 60, r: 24, fill: 'yellow'
|
242
|
-
end
|
243
|
-
```
|
244
|
-
|
245
|
-
Another approach to a more modular SVG composition, would be to subclass
|
246
|
-
`Victor::SVG`.
|
247
|
-
|
248
|
-
See the [composite svg example](https://github.com/DannyBen/victor/tree/master/examples#14-composite-svg)
|
249
|
-
or the [subclassing example](https://github.com/DannyBen/victor/tree/master/examples#15-subclassing)
|
250
|
-
for more details.
|
251
|
-
|
252
|
-
|
253
|
-
### Saving the Output
|
254
|
-
|
255
|
-
Generate the full SVG to a string with `render`:
|
256
|
-
|
257
|
-
```ruby
|
258
|
-
result = svg.render
|
259
|
-
```
|
260
|
-
|
261
|
-
Or, save it to a file with `save`:
|
262
|
-
|
263
|
-
```ruby
|
264
|
-
svg.save 'filename'
|
265
|
-
# the '.svg' extension is optional
|
266
|
-
```
|
36
|
+
setup viewBox: '0 0 100 100'
|
267
37
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
inside HTML, you can change the SVG template:
|
273
|
-
|
274
|
-
```ruby
|
275
|
-
svg = Victor::SVG.new template: :html
|
276
|
-
# accepts :html, :minimal, :default or a filename
|
277
|
-
```
|
278
|
-
|
279
|
-
You can also point it to any other template file:
|
280
|
-
|
281
|
-
```ruby
|
282
|
-
svg = Victor::SVG.new template: 'path/to/template.svg'
|
283
|
-
```
|
284
|
-
|
285
|
-
See the [templates] folder for an understanding of how templates are
|
286
|
-
structured.
|
287
|
-
|
288
|
-
Templates can also be provided when rendering or saving the output:
|
289
|
-
|
290
|
-
```ruby
|
291
|
-
svg.save 'filename', template: :minimal
|
292
|
-
svg.render template: :minimal
|
293
|
-
```
|
294
|
-
|
295
|
-
|
296
|
-
### CSS
|
297
|
-
|
298
|
-
CSS gets a special treatment in `Victor::SVG`, with these objectives in mind:
|
299
|
-
|
300
|
-
- Hide implementation details (such as the need for a `CDATA` marker)
|
301
|
-
- Provide a DSL-like syntax for CSS rules
|
302
|
-
|
303
|
-
The `Victor::SVG` objects has a `css` property, which can contain either a
|
304
|
-
Hash or a String:
|
305
|
-
|
306
|
-
```ruby
|
307
|
-
svg = Victor::SVG.new
|
308
|
-
|
309
|
-
svg.css = css_hash_or_string
|
310
|
-
# or without the equal sign:
|
311
|
-
svg.css css_hash_or_string
|
312
|
-
|
313
|
-
svg.build do
|
314
|
-
# ...
|
315
|
-
end
|
316
|
-
```
|
317
|
-
|
318
|
-
This flexibility allows you to apply CSS in multiple ways. Below are some
|
319
|
-
examples.
|
320
|
-
|
321
|
-
#### Assigning CSS rules using the hash syntax
|
322
|
-
|
323
|
-
```ruby
|
324
|
-
svg = Victor::SVG.new
|
325
|
-
|
326
|
-
svg.build do
|
327
|
-
css['.main'] = {
|
328
|
-
stroke: "green",
|
329
|
-
stroke_width: 2,
|
330
|
-
fill: "yellow"
|
331
|
-
}
|
332
|
-
|
333
|
-
circle cx: 35, cy: 35, r: 20, class: 'main'
|
334
|
-
end
|
335
|
-
```
|
336
|
-
|
337
|
-
#### Assigning a full hash to the CSS property
|
338
|
-
|
339
|
-
```ruby
|
340
|
-
svg.css = {
|
341
|
-
'.bar': {
|
342
|
-
fill: '#666',
|
343
|
-
stroke: '#fff',
|
344
|
-
stroke_width: 1
|
345
|
-
},
|
346
|
-
'.negative': {
|
347
|
-
fill: '#f66'
|
348
|
-
},
|
349
|
-
'.positive': {
|
350
|
-
fill: '#6f6'
|
351
|
-
}
|
352
|
-
}
|
353
|
-
```
|
354
|
-
|
355
|
-
Underscore characters will be converted to dashes (`stroke_width` becomes
|
356
|
-
`stroke-width`).
|
357
|
-
|
358
|
-
#### Importing CSS from an external file
|
359
|
-
|
360
|
-
```ruby
|
361
|
-
svg.css = File.read 'styles.css'
|
362
|
-
```
|
363
|
-
|
364
|
-
#### CSS `@import` directives
|
365
|
-
|
366
|
-
If you need to add CSS statements , like `@import`, use the following syntax:
|
367
|
-
|
368
|
-
```ruby
|
369
|
-
css['@import'] = [
|
370
|
-
"url('https://fonts.googleapis.com/css?family=Audiowide')",
|
371
|
-
"url('https://fonts.googleapis.com/css?family=Pacifico')"
|
372
|
-
]
|
373
|
-
```
|
374
|
-
|
375
|
-
This is achieved thanks to the fact that when Victor encounters an array
|
376
|
-
in the CSS hash, it will prefix each of the array elements with the hash
|
377
|
-
key, so the above will result in two `@import url(...)` rows.
|
378
|
-
|
379
|
-
See the [css example](https://github.com/DannyBen/victor/tree/master/examples#08-css),
|
380
|
-
[css string example](https://github.com/DannyBen/victor/tree/master/examples#09-css-string),
|
381
|
-
or the [custom fonts example](https://github.com/DannyBen/victor/tree/master/examples#13-custom-fonts).
|
382
|
-
|
383
|
-
|
384
|
-
### Tagless Elements
|
385
|
-
|
386
|
-
Using underscore (`_`) as the element name will simply add the value to the
|
387
|
-
generated SVG, without any surrounding element. This is designed to allow
|
388
|
-
generating something like this:
|
389
|
-
|
390
|
-
```xml
|
391
|
-
<text>
|
392
|
-
You are
|
393
|
-
<tspan font-weight="bold">not</tspan>
|
394
|
-
a banana
|
395
|
-
</text>
|
396
|
-
```
|
397
|
-
|
398
|
-
using this Ruby code:
|
38
|
+
build do
|
39
|
+
rect x: 0, y: 0, width: 100, height: 100, fill: :white
|
40
|
+
circle cx: 50, cy: 50, r: 40, fill: 'yellow'
|
41
|
+
rect x: 10, y: 50, width: 80, height: 50, fill: :yellow
|
399
42
|
|
400
|
-
|
401
|
-
|
402
|
-
text do
|
403
|
-
_ 'You are'
|
404
|
-
tspan 'not', font_weight: "bold"
|
405
|
-
_ 'a banana'
|
43
|
+
[25, 50].each do |x|
|
44
|
+
circle cx: x, cy: 40, r: 8, fill: :white
|
406
45
|
end
|
407
|
-
end
|
408
|
-
```
|
409
|
-
|
410
|
-
See the [tagless elements example](https://github.com/DannyBen/victor/tree/master/examples#17-tagless-elements).
|
411
|
-
|
412
|
-
|
413
|
-
### XML Encoding
|
414
46
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
text "Ben & Jerry's"
|
420
|
-
end
|
421
|
-
# <text>Ben & Jerry's</text>
|
422
|
-
```
|
423
|
-
|
424
|
-
If you need to use the raw, unencoded string, add `!` to the element's name:
|
425
|
-
|
426
|
-
```ruby
|
427
|
-
svg.build do
|
428
|
-
text! "Ben & Jerry's"
|
47
|
+
path fill: 'white', d: %w[
|
48
|
+
M11 100 l13 -15 l13 15 l13 -15
|
49
|
+
l13 15 l13 -15 l13 15 Z
|
50
|
+
]
|
429
51
|
end
|
430
|
-
# <text>Ben & Jerry's</text>
|
431
52
|
```
|
432
53
|
|
433
|
-
|
54
|
+
</td></tr></table>
|
434
55
|
|
435
56
|
|
436
|
-
|
437
|
-
|
438
|
-
By default, the generated SVGs will have a newline glue between the elements.
|
439
|
-
You can change this (for example, to an empty string) if the default newlines
|
440
|
-
are not appropriate for your use case.
|
441
|
-
|
442
|
-
```ruby
|
443
|
-
svg = Victor::SVG.new glue: ''
|
444
|
-
```
|
445
|
-
|
446
|
-
The glue can also be provided when rendering or saving the output:
|
447
|
-
|
448
|
-
```ruby
|
449
|
-
svg.save 'filename', glue: ''
|
450
|
-
svg.render glue: ''
|
451
|
-
```
|
452
|
-
|
453
|
-
### DSL Syntax
|
454
|
-
|
455
|
-
Victor also supports a DSL-like syntax. To use it, simply `require 'victor/script'`.
|
456
|
-
|
457
|
-
Once required, you have access to:
|
458
|
-
|
459
|
-
- `svg` - returns an instance of `Victor::SVG`
|
460
|
-
- All the methods that are available on the `SVG` object, are included at the root level.
|
461
|
-
|
462
|
-
For example:
|
463
|
-
|
464
|
-
```ruby
|
465
|
-
require 'victor/script'
|
466
|
-
|
467
|
-
setup width: 100, height: 100
|
468
|
-
|
469
|
-
build do
|
470
|
-
circle cx: 50, cy: 50, r: 30, fill: "yellow"
|
471
|
-
end
|
472
|
-
|
473
|
-
puts render
|
474
|
-
save 'output.svg'
|
475
|
-
```
|
476
|
-
|
477
|
-
See the [dsl example](https://github.com/DannyBen/victor/tree/master/examples#19-dsl).
|
478
|
-
|
479
|
-
## Using with Rails
|
480
|
-
|
481
|
-
See the [example_rails](example_rails) folder.
|
482
|
-
|
483
|
-
|
484
|
-
## Related Projects
|
485
|
-
|
486
|
-
### [Victor CLI][victor-cli]
|
487
|
-
|
488
|
-
A command line utility that allows converting Ruby to SVG as well as SVG to
|
489
|
-
Victor Ruby scripts.
|
490
|
-
|
491
|
-
### [Victor Opal][victor-opal]
|
492
|
-
|
493
|
-
A Victor playground that works in the browser.
|
494
|
-
|
495
|
-
### [Minichart][minichart]
|
496
|
-
|
497
|
-
A Ruby gem that uses Victor to generate SVG charts
|
498
|
-
|
499
|
-
[][minichart]
|
500
|
-
|
501
|
-
|
502
|
-
### [Icodi][icodi]
|
503
|
-
|
504
|
-
A Ruby gem that uses Victor to generate consistent random icon
|
505
|
-
images, similar to GitHub's identicon.
|
506
|
-
|
507
|
-
[][icodi]
|
57
|
+
## Documentation
|
508
58
|
|
59
|
+
- [Victor Homepage][docs]
|
509
60
|
|
510
61
|
## Contributing / Support
|
511
62
|
|
512
63
|
If you experience any issue, have a question or a suggestion, or if you wish
|
513
|
-
to contribute, feel free to [open an issue][issues]
|
514
|
-
|
515
|
-
---
|
64
|
+
to contribute, feel free to [open an issue][issues] or
|
65
|
+
[start a discussion][discussions].
|
516
66
|
|
517
|
-
[examples]: https://github.com/DannyBen/victor/tree/master/examples#examples
|
518
|
-
[templates]: https://github.com/DannyBen/victor/tree/master/lib/victor/templates
|
519
|
-
[icodi]: https://github.com/DannyBen/icodi
|
520
|
-
[minichart]: https://github.com/DannyBen/minichart
|
521
|
-
[victor-opal]: https://kuboon.github.io/victor-opal/
|
522
|
-
[victor-cli]: https://github.com/DannyBen/victor-cli
|
523
67
|
[issues]: https://github.com/DannyBen/victor/issues
|
68
|
+
[discussions]: https://github.com/DannyBen/victor/discussions
|
69
|
+
[docs]: https://victor.dannyb.co/
|
data/lib/victor/attributes.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
module Victor
|
2
|
-
|
3
2
|
# Handles conversion from a Hash of attributes, to an XML string or
|
4
3
|
# a CSS string.
|
5
4
|
class Attributes
|
6
5
|
attr_reader :attributes
|
7
6
|
|
8
|
-
def initialize(attributes={})
|
7
|
+
def initialize(attributes = {})
|
9
8
|
@attributes = attributes
|
10
9
|
end
|
11
10
|
|
@@ -13,10 +12,11 @@ module Victor
|
|
13
12
|
mapped = attributes.map do |key, value|
|
14
13
|
key = key.to_s.tr '_', '-'
|
15
14
|
|
16
|
-
|
15
|
+
case value
|
16
|
+
when Hash
|
17
17
|
style = Attributes.new(value).to_style
|
18
18
|
"#{key}=\"#{style}\""
|
19
|
-
|
19
|
+
when Array
|
20
20
|
"#{key}=\"#{value.join ' '}\""
|
21
21
|
else
|
22
22
|
"#{key}=#{value.to_s.encode(xml: :attr)}"
|
@@ -42,7 +42,5 @@ module Victor
|
|
42
42
|
def []=(key, value)
|
43
43
|
attributes[key] = value
|
44
44
|
end
|
45
|
-
|
46
45
|
end
|
47
|
-
|
48
|
-
end
|
46
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Victor
|
4
|
+
class Component
|
5
|
+
extend Forwardable
|
6
|
+
include Marshaling
|
7
|
+
|
8
|
+
def_delegators :svg, :save, :render, :content, :element, :tag, :css, :to_s
|
9
|
+
|
10
|
+
# Marshaling data
|
11
|
+
def marshaling = %i[width height x y svg merged_css]
|
12
|
+
|
13
|
+
# Subclasses MUST implement this
|
14
|
+
def body
|
15
|
+
raise(NotImplementedError, "#{self.class.name} must implement `body'")
|
16
|
+
end
|
17
|
+
|
18
|
+
# Subclasses MUST override these methods, OR assign instance vars
|
19
|
+
def height
|
20
|
+
@height || raise(NotImplementedError,
|
21
|
+
"#{self.class.name} must implement `height' or `@height'")
|
22
|
+
end
|
23
|
+
|
24
|
+
def width
|
25
|
+
@width || raise(NotImplementedError,
|
26
|
+
"#{self.class.name} must implement `width' or `@width'")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Subclasses MAY override these methods, OR assign instance vars
|
30
|
+
def style = @style ||= {}
|
31
|
+
def x = @x ||= 0
|
32
|
+
def y = @y ||= 0
|
33
|
+
|
34
|
+
# Appending/Embedding - DSL for the `#body` implementation
|
35
|
+
def append(component)
|
36
|
+
svg_instance.append component.svg
|
37
|
+
merged_css.merge! component.merged_css
|
38
|
+
end
|
39
|
+
alias embed append
|
40
|
+
|
41
|
+
# SVG / CSS
|
42
|
+
def svg
|
43
|
+
@svg ||= begin
|
44
|
+
body
|
45
|
+
svg_instance.css = merged_css
|
46
|
+
svg_instance
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
# Start with an ordinary SVG instance
|
53
|
+
def svg_instance = @svg_instance ||= SVG.new(viewBox: "#{x} #{y} #{width} #{height}")
|
54
|
+
|
55
|
+
# Internal DSL to enable `add.anything` in the `#body` implementation
|
56
|
+
alias add svg_instance
|
57
|
+
|
58
|
+
# Start with a copy of our own style
|
59
|
+
def merged_css = @merged_css ||= style.dup
|
60
|
+
end
|
61
|
+
end
|
data/lib/victor/css.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Victor
|
2
|
-
|
3
2
|
class CSS
|
4
3
|
attr_reader :attributes
|
5
4
|
|
@@ -13,12 +12,13 @@ module Victor
|
|
13
12
|
|
14
13
|
def render
|
15
14
|
return '' if attributes.empty?
|
16
|
-
|
15
|
+
|
16
|
+
%[<style>\n#{self}\n</style>\n]
|
17
17
|
end
|
18
18
|
|
19
19
|
protected
|
20
20
|
|
21
|
-
def convert_hash(hash, indent=2)
|
21
|
+
def convert_hash(hash, indent = 2)
|
22
22
|
return hash unless hash.is_a? Hash
|
23
23
|
|
24
24
|
result = []
|
@@ -33,13 +33,14 @@ module Victor
|
|
33
33
|
def css_block(key, value, indent)
|
34
34
|
result = []
|
35
35
|
|
36
|
-
my_indent =
|
36
|
+
my_indent = ' ' * indent
|
37
37
|
|
38
|
-
|
38
|
+
case value
|
39
|
+
when Hash
|
39
40
|
result.push "#{my_indent}#{key} {"
|
40
|
-
result.push convert_hash(value, indent+2)
|
41
|
+
result.push convert_hash(value, indent + 2)
|
41
42
|
result.push "#{my_indent}}"
|
42
|
-
|
43
|
+
when Array
|
43
44
|
value.each do |row|
|
44
45
|
result.push "#{my_indent}#{key} #{row};"
|
45
46
|
end
|
@@ -50,5 +51,4 @@ module Victor
|
|
50
51
|
result
|
51
52
|
end
|
52
53
|
end
|
53
|
-
|
54
|
-
end
|
54
|
+
end
|
data/lib/victor/dsl.rb
CHANGED
@@ -3,7 +3,7 @@ require 'forwardable'
|
|
3
3
|
module Victor
|
4
4
|
module DSL
|
5
5
|
extend Forwardable
|
6
|
-
def_delegators :svg, :setup, :build, :save, :render, :append, :element, :css
|
6
|
+
def_delegators :svg, :setup, :build, :save, :render, :append, :element, :tag, :css
|
7
7
|
|
8
8
|
def svg
|
9
9
|
@svg ||= Victor::SVG.new
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Victor
|
2
|
+
module Marshaling
|
3
|
+
def marshaling
|
4
|
+
raise NotImplementedError, "#{self.class.name} must implement `marshaling'"
|
5
|
+
end
|
6
|
+
|
7
|
+
# YAML serialization methods
|
8
|
+
def encode_with(coder)
|
9
|
+
marshaling.each do |attr|
|
10
|
+
coder[attr.to_s] = send(attr)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def init_with(coder)
|
15
|
+
marshaling.each do |attr|
|
16
|
+
instance_variable_set(:"@#{attr}", coder[attr.to_s])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Marshal serialization methods
|
21
|
+
def marshal_dump
|
22
|
+
marshaling.to_h do |attr|
|
23
|
+
[attr, send(attr)]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def marshal_load(data)
|
28
|
+
marshaling.each do |attr|
|
29
|
+
instance_variable_set(:"@#{attr}", data[attr])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/victor/svg.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
module Victor
|
2
2
|
class SVG < SVGBase
|
3
|
-
def method_missing(method_sym,
|
4
|
-
|
3
|
+
def method_missing(method_sym, ...)
|
4
|
+
tag(method_sym, ...)
|
5
|
+
end
|
6
|
+
|
7
|
+
def respond_to_missing?(*)
|
8
|
+
true
|
5
9
|
end
|
6
10
|
end
|
7
|
-
end
|
11
|
+
end
|
data/lib/victor/svg_base.rb
CHANGED
@@ -1,24 +1,31 @@
|
|
1
1
|
module Victor
|
2
|
-
|
3
2
|
class SVGBase
|
3
|
+
include Marshaling
|
4
|
+
|
4
5
|
attr_accessor :template, :glue
|
5
6
|
attr_reader :content, :svg_attributes
|
7
|
+
attr_writer :css
|
6
8
|
|
7
9
|
def initialize(attributes = nil, &block)
|
8
10
|
setup attributes
|
9
11
|
@content = []
|
10
|
-
build
|
12
|
+
build(&block) if block
|
13
|
+
end
|
14
|
+
|
15
|
+
def marshaling
|
16
|
+
%i[template glue svg_attributes css content]
|
11
17
|
end
|
12
18
|
|
13
19
|
def <<(additional_content)
|
14
20
|
content.push additional_content.to_s
|
15
21
|
end
|
16
22
|
alias append <<
|
23
|
+
alias embed <<
|
17
24
|
|
18
25
|
def setup(attributes = nil)
|
19
26
|
attributes ||= {}
|
20
|
-
attributes[:width] ||=
|
21
|
-
attributes[:height] ||=
|
27
|
+
attributes[:width] ||= '100%'
|
28
|
+
attributes[:height] ||= '100%'
|
22
29
|
|
23
30
|
@template = attributes[:template] || @template || :default
|
24
31
|
@glue = attributes[:glue] || @glue || "\n"
|
@@ -30,10 +37,10 @@ module Victor
|
|
30
37
|
end
|
31
38
|
|
32
39
|
def build(&block)
|
33
|
-
|
40
|
+
instance_eval(&block)
|
34
41
|
end
|
35
42
|
|
36
|
-
def
|
43
|
+
def tag(name, value = nil, attributes = {})
|
37
44
|
if value.is_a? Hash
|
38
45
|
attributes = value
|
39
46
|
value = nil
|
@@ -50,17 +57,18 @@ module Victor
|
|
50
57
|
empty_tag = name.to_s == '_'
|
51
58
|
|
52
59
|
if block_given? || value
|
53
|
-
content.push "<#{name} #{attributes}".strip
|
60
|
+
content.push "#{"<#{name} #{attributes}".strip}>" unless empty_tag
|
54
61
|
if value
|
55
62
|
content.push(escape ? value.to_s.encode(xml: :text) : value)
|
56
63
|
else
|
57
64
|
yield
|
58
65
|
end
|
59
66
|
content.push "</#{name}>" unless empty_tag
|
60
|
-
else
|
67
|
+
else
|
61
68
|
content.push "<#{name} #{attributes}/>"
|
62
69
|
end
|
63
70
|
end
|
71
|
+
alias element tag
|
64
72
|
|
65
73
|
def css(defs = nil)
|
66
74
|
@css ||= {}
|
@@ -68,20 +76,16 @@ module Victor
|
|
68
76
|
@css
|
69
77
|
end
|
70
78
|
|
71
|
-
def css=(defs)
|
72
|
-
@css = defs
|
73
|
-
end
|
74
|
-
|
75
79
|
def render(template: nil, glue: nil)
|
76
80
|
@template = template if template
|
77
81
|
@glue = glue if glue
|
78
82
|
css_handler = CSS.new css
|
79
83
|
|
80
84
|
svg_template % {
|
81
|
-
css:
|
82
|
-
style:
|
85
|
+
css: css_handler,
|
86
|
+
style: css_handler.render,
|
83
87
|
attributes: svg_attributes,
|
84
|
-
content:
|
88
|
+
content: to_s,
|
85
89
|
}
|
86
90
|
end
|
87
91
|
|
@@ -90,7 +94,7 @@ module Victor
|
|
90
94
|
end
|
91
95
|
|
92
96
|
def save(filename, template: nil, glue: nil)
|
93
|
-
filename = "#{filename}.svg" unless
|
97
|
+
filename = "#{filename}.svg" unless /\..{2,4}$/.match?(filename)
|
94
98
|
File.write filename, render(template: template, glue: glue)
|
95
99
|
end
|
96
100
|
|
@@ -108,5 +112,4 @@ module Victor
|
|
108
112
|
end
|
109
113
|
end
|
110
114
|
end
|
111
|
-
|
112
|
-
end
|
115
|
+
end
|
@@ -1,11 +1,4 @@
|
|
1
|
-
|
2
|
-
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
3
|
-
|
4
|
-
<svg %{attributes}
|
5
|
-
xmlns="http://www.w3.org/2000/svg"
|
6
|
-
xmlns:xlink="http://www.w3.org/1999/xlink">
|
7
|
-
|
1
|
+
<svg %{attributes} xmlns="http://www.w3.org/2000/svg">
|
8
2
|
%{style}
|
9
3
|
%{content}
|
10
|
-
|
11
|
-
</svg>
|
4
|
+
</svg>
|
data/lib/victor/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Victor
|
2
|
-
VERSION =
|
3
|
-
end
|
2
|
+
VERSION = '0.5.0'
|
3
|
+
end
|
data/lib/victor.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'victor/version'
|
2
|
-
require 'victor/svg_base'
|
3
|
-
require 'victor/svg'
|
4
|
-
require 'victor/attributes'
|
5
|
-
require 'victor/css'
|
6
|
-
require 'victor/dsl'
|
7
2
|
|
8
|
-
|
3
|
+
module Victor
|
4
|
+
autoload :Attributes, 'victor/attributes'
|
5
|
+
autoload :Component, 'victor/component'
|
6
|
+
autoload :CSS, 'victor/css'
|
7
|
+
autoload :DSL, 'victor/dsl'
|
8
|
+
autoload :Marshaling, 'victor/marshaling'
|
9
|
+
autoload :SVG, 'victor/svg'
|
10
|
+
autoload :SVGBase, 'victor/svg_base'
|
11
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: victor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Danny Ben Shitrit
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Build SVG images with ease
|
14
14
|
email: db@dannyben.com
|
@@ -19,20 +19,26 @@ files:
|
|
19
19
|
- README.md
|
20
20
|
- lib/victor.rb
|
21
21
|
- lib/victor/attributes.rb
|
22
|
+
- lib/victor/component.rb
|
22
23
|
- lib/victor/css.rb
|
23
24
|
- lib/victor/dsl.rb
|
25
|
+
- lib/victor/marshaling.rb
|
24
26
|
- lib/victor/script.rb
|
25
27
|
- lib/victor/svg.rb
|
26
28
|
- lib/victor/svg_base.rb
|
27
29
|
- lib/victor/templates/default.svg
|
28
|
-
- lib/victor/templates/html.svg
|
29
30
|
- lib/victor/templates/minimal.svg
|
30
31
|
- lib/victor/version.rb
|
31
32
|
homepage: https://github.com/DannyBen/victor
|
32
33
|
licenses:
|
33
34
|
- MIT
|
34
|
-
metadata:
|
35
|
-
|
35
|
+
metadata:
|
36
|
+
bug_tracker_uri: https://github.com/DannyBen/victor/issues
|
37
|
+
changelog_uri: https://github.com/DannyBen/victor/blob/master/CHANGELOG.md
|
38
|
+
homepage_uri: https://victor.dannyb.co/
|
39
|
+
source_code_uri: https://github.com/DannyBen/victor
|
40
|
+
rubygems_mfa_required: 'true'
|
41
|
+
post_install_message:
|
36
42
|
rdoc_options: []
|
37
43
|
require_paths:
|
38
44
|
- lib
|
@@ -40,15 +46,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
40
46
|
requirements:
|
41
47
|
- - ">="
|
42
48
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
49
|
+
version: 3.0.0
|
44
50
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
51
|
requirements:
|
46
52
|
- - ">="
|
47
53
|
- !ruby/object:Gem::Version
|
48
54
|
version: '0'
|
49
55
|
requirements: []
|
50
|
-
rubygems_version: 3.
|
51
|
-
signing_key:
|
56
|
+
rubygems_version: 3.5.17
|
57
|
+
signing_key:
|
52
58
|
specification_version: 4
|
53
59
|
summary: SVG Builder
|
54
60
|
test_files: []
|