svg_pathify 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +26 -0
- data/lib/svg_pathify/shape.rb +55 -0
- data/lib/svg_pathify/shapes/circle.rb +22 -0
- data/lib/svg_pathify/shapes/ellipse.rb +20 -0
- data/lib/svg_pathify/shapes/line.rb +21 -0
- data/lib/svg_pathify/shapes/polygon.rb +31 -0
- data/lib/svg_pathify/shapes/rect.rb +16 -0
- data/lib/svg_pathify/to_short_f.rb +12 -0
- data/lib/svg_pathify.rb +53 -0
- data/test/svg_pathify_test.rb +94 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3b85d9b461f4ce5d4cd3653458bee1c601ee1791
|
4
|
+
data.tar.gz: 05ec30b4bbb13c0546b9e13e2375db1c5fc96b15
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4c58f24294519ad59fcbf51e72cf2a86913d5e330349163dc4dbcd087082330462f12343256697f888cd368d97dbbbd15a0199b2026a83e30dee485c33f2e233
|
7
|
+
data.tar.gz: 367deaf9db8dc2cec4d183d54f199d1631264324f91c483d88472fa34a63cffb0d77aa8fd0e0e93d6b458acad1e1991efecd9f033fdc907b56690ec9ea122dd4
|
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
**svg_pathify** turns svg [basic shapes](http://www.w3.org/TR/SVG/shapes.html) into path svg elements.
|
2
|
+
|
3
|
+
## install
|
4
|
+
|
5
|
+
~~~
|
6
|
+
gem install svg_pathify
|
7
|
+
~~~
|
8
|
+
|
9
|
+
or in your Gemfile:
|
10
|
+
|
11
|
+
~~~
|
12
|
+
gem 'svg_pathify'
|
13
|
+
~~~
|
14
|
+
|
15
|
+
## usage
|
16
|
+
|
17
|
+
|
18
|
+
~~~ruby
|
19
|
+
input = %Q{<polyline points="350,75 379,161 469,161 397,215
|
20
|
+
423,301 350,250 277,301 303,215
|
21
|
+
231,161 321,161" />}
|
22
|
+
|
23
|
+
output = SvgPathify.convert( input )
|
24
|
+
#=> '<path d="M350,75L379,161L469,161L397,215L423,301L350,250L277,301L303,215L231,161L321,161Z" />'
|
25
|
+
~~~
|
26
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module SvgPathify
|
2
|
+
|
3
|
+
class Shape
|
4
|
+
|
5
|
+
attr_accessor :node, :path, :special_attrs
|
6
|
+
|
7
|
+
def initialize( node )
|
8
|
+
@node = node
|
9
|
+
special_attrs && special_attrs.each do |attr|
|
10
|
+
self.send "#{attr}=", node[attr]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_path_element
|
15
|
+
node.document.create_element 'path', clean_attributes.merge( d: path_commands )
|
16
|
+
end
|
17
|
+
|
18
|
+
def path_commands
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def clean_attributes
|
23
|
+
node.attributes.reject {|k,v| attributes_to_delete.include?(k) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def attributes_to_delete
|
27
|
+
[]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.inherited( clz )
|
31
|
+
def clz.special_attr( *attrs )
|
32
|
+
class_eval do
|
33
|
+
attr_accessor *attrs
|
34
|
+
|
35
|
+
define_method :attributes_to_delete do
|
36
|
+
attrs.map &:to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
define_method :special_attrs do
|
40
|
+
attrs
|
41
|
+
end
|
42
|
+
|
43
|
+
attrs.each do |the_attr|
|
44
|
+
define_method the_attr do
|
45
|
+
instance_variable_get( "@#{the_attr}" ).to_short_f
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module SvgPathify
|
2
|
+
|
3
|
+
module Shapes
|
4
|
+
|
5
|
+
class Circle < ::SvgPathify::Shape
|
6
|
+
|
7
|
+
special_attr :cx, :cy, :r
|
8
|
+
|
9
|
+
def path_commands
|
10
|
+
[
|
11
|
+
"M#{cx} #{cy}",
|
12
|
+
"m#{-r} 0",
|
13
|
+
"a#{r},#{r} 0 1,0 #{r * 2},0",
|
14
|
+
"a#{r},#{r} 0 1,0 -#{r * 2},0",
|
15
|
+
"Z"
|
16
|
+
].join
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SvgPathify
|
2
|
+
|
3
|
+
module Shapes
|
4
|
+
|
5
|
+
class Ellipse < ::SvgPathify::Shape
|
6
|
+
|
7
|
+
special_attr :cx, :cy, :rx, :ry
|
8
|
+
|
9
|
+
def path_commands
|
10
|
+
[
|
11
|
+
"M#{cx-rx} #{cy}",
|
12
|
+
"a#{rx},#{ry},0,1,1,#{cx-rx},#{cy+1}",
|
13
|
+
"Z"
|
14
|
+
].join
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SvgPathify
|
2
|
+
|
3
|
+
module Shapes
|
4
|
+
|
5
|
+
class Line < ::SvgPathify::Shape
|
6
|
+
|
7
|
+
special_attr :x1, :y1, :x2, :y2
|
8
|
+
|
9
|
+
def path_commands
|
10
|
+
[
|
11
|
+
"M#{x1} #{y1}",
|
12
|
+
"L#{x2} #{y2}",
|
13
|
+
"L#{x1} #{y1}",
|
14
|
+
"Z"
|
15
|
+
].join
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SvgPathify
|
2
|
+
|
3
|
+
module Shapes
|
4
|
+
|
5
|
+
# Example:
|
6
|
+
# <polygon fill="#ED1C24" points="68.793,3.148 51.865,19 86.795,19 "/>
|
7
|
+
class Polygon < ::SvgPathify::Shape
|
8
|
+
|
9
|
+
def path_commands
|
10
|
+
pts = node['points'].split.map {|pos| pos.split(',').map(&:to_short_f) }
|
11
|
+
|
12
|
+
paths = []
|
13
|
+
pts.each_with_index do |dot, i|
|
14
|
+
if i.zero?
|
15
|
+
paths << "M#{dot.join ?,}"
|
16
|
+
else
|
17
|
+
paths << "L#{dot.join ?,}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
paths << "Z"
|
21
|
+
paths.join
|
22
|
+
end
|
23
|
+
|
24
|
+
def attributes_to_delete
|
25
|
+
"points"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/svg_pathify.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require_relative 'svg_pathify/to_short_f'
|
3
|
+
require_relative 'svg_pathify/shape'
|
4
|
+
|
5
|
+
Dir.glob( File.expand_path( "svg_pathify/shapes/*.rb", File.dirname(__FILE__) ) ) do |shape|
|
6
|
+
require shape
|
7
|
+
end
|
8
|
+
|
9
|
+
module SvgPathify
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def convert svg_xml
|
13
|
+
Converter.new(svg_xml).output
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Converter
|
18
|
+
|
19
|
+
attr_reader :input
|
20
|
+
|
21
|
+
def initialize( svg )
|
22
|
+
@xml = Nokogiri::XML( svg, &:noblanks )
|
23
|
+
@converted_root = convert_node @xml.root
|
24
|
+
end
|
25
|
+
|
26
|
+
def output
|
27
|
+
@converted_root.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
|
33
|
+
CONVERTING_MAP = {
|
34
|
+
:rect => ::SvgPathify::Shapes::Rect,
|
35
|
+
:circle => ::SvgPathify::Shapes::Circle,
|
36
|
+
:polygon => ::SvgPathify::Shapes::Polygon,
|
37
|
+
:polyline => ::SvgPathify::Shapes::Polygon,
|
38
|
+
:line => ::SvgPathify::Shapes::Line,
|
39
|
+
:ellipse => ::SvgPathify::Shapes::Ellipse
|
40
|
+
}
|
41
|
+
|
42
|
+
def convert_node( node )
|
43
|
+
return node if node.text?
|
44
|
+
|
45
|
+
type = CONVERTING_MAP[node.name.to_sym]
|
46
|
+
return node if type.nil?
|
47
|
+
|
48
|
+
type.new( node ).to_path_element
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
$: << File.expand_path( '../lib/', File.basename(__FILE__) )
|
3
|
+
|
4
|
+
require 'svg_pathify'
|
5
|
+
|
6
|
+
class SvgPathifyTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_nothing_changed_if_no_shape_available
|
9
|
+
input = %Q{<path d="M93.992 83.676m-67.244 0a67.244,67.244 0 1,0 134.488,0a67.244,67.244 0 1,0 -134.488,0Z" />}
|
10
|
+
|
11
|
+
assert_xml_equal input, SvgPathify.convert( input )
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_rect_changes_to_path_tag
|
15
|
+
input = %Q{<rect x="100" y="300" width="50" height="200" />}
|
16
|
+
output = %Q{<path x="100" y="300" d="M0 0l50 0l0 200l-50 0l0 -200Z" />}
|
17
|
+
|
18
|
+
assert_xml_equal output, SvgPathify.convert( input )
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_circle_changes_to_path_tag
|
22
|
+
input = %Q{<circle x="100" y="300" r="50" cx="100" cy="200" />}
|
23
|
+
output = %Q{<path x="100" y="300" d="M100 200m-50 0a50,50 0 1,0 100,0a50,50 0 1,0 -100,0Z" />}
|
24
|
+
|
25
|
+
assert_xml_equal output, SvgPathify.convert( input )
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_polygon_changes_to_path_tag
|
29
|
+
input = %Q{<polygon points="350,75 379,161 469,161 397,215
|
30
|
+
423,301 350,250 277,301 303,215
|
31
|
+
231,161 321,161" />}
|
32
|
+
output = %Q{<path d="M350,75L379,161L469,161L397,215L423,301L350,250L277,301L303,215L231,161L321,161Z" />}
|
33
|
+
|
34
|
+
assert_xml_equal output, SvgPathify.convert( input )
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_polyline_changes_to_path_tag
|
38
|
+
input = %Q{<polyline points="350,75 379,161 469,161 397,215
|
39
|
+
423,301 350,250 277,301 303,215
|
40
|
+
231,161 321,161" />}
|
41
|
+
output = %Q{<path d="M350,75L379,161L469,161L397,215L423,301L350,250L277,301L303,215L231,161L321,161Z" />}
|
42
|
+
|
43
|
+
assert_xml_equal output, SvgPathify.convert( input )
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_line_changes_to_path_tag
|
47
|
+
input = %Q{<line x1="900" y1="300" x2="1100" y2="100" stroke-width="25" />}
|
48
|
+
output = %Q{<path d="M900 300L1100 100L900 300Z" stroke-width="25" />}
|
49
|
+
|
50
|
+
assert_xml_equal output, SvgPathify.convert( input )
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_ellipse_changes_to_path_tag
|
54
|
+
input = %Q{<ellipse
|
55
|
+
rx="250" ry="100"
|
56
|
+
fill="none" stroke="blue" stroke-width="20" />}
|
57
|
+
output = %Q{<path d="M-250 0a250,100,0,1,1,-250,1Z"
|
58
|
+
stroke-width="20"
|
59
|
+
fill="none"
|
60
|
+
stroke="blue" />}
|
61
|
+
|
62
|
+
assert_xml_equal output, SvgPathify.convert( input )
|
63
|
+
end
|
64
|
+
|
65
|
+
#-----> helper
|
66
|
+
|
67
|
+
def assert_xml_equal( expect, other, msg=nil )
|
68
|
+
assert_equal Nokogiri.parse( expect ).root, Nokogiri.parse( other ).root
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
class Nokogiri::XML::Node
|
74
|
+
# Return true if this node is content-equivalent to other, false otherwise
|
75
|
+
def == (other)
|
76
|
+
return true if self.object_id == other.object_id
|
77
|
+
return false if other.nil?
|
78
|
+
return false unless name == other.name
|
79
|
+
stype = node_type; otype = other.node_type
|
80
|
+
return false unless stype == otype
|
81
|
+
sa = attributes; oa = other.attributes
|
82
|
+
return false unless sa.length == oa.length
|
83
|
+
sa = sa.sort.map{ |n,a| [n,a.value,a.namespace && a.namespace.href] }
|
84
|
+
oa = oa.sort.map{ |n,a| [n,a.value,a.namespace && a.namespace.href] }
|
85
|
+
return false unless sa == oa
|
86
|
+
skids = children; okids = other.children
|
87
|
+
return false unless skids.length == okids.length
|
88
|
+
return false if stype == TEXT_NODE && (content != other.content)
|
89
|
+
sns = namespace; ons = other.namespace
|
90
|
+
return false if !sns ^ !ons
|
91
|
+
return false if sns && (sns.href != ons.href)
|
92
|
+
skids.to_enum.with_index.all?{ |ski,i| ski =~ okids[i] }
|
93
|
+
end
|
94
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: svg_pathify
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- qhwa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-12 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email: qhwa@163.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- README.md
|
20
|
+
- lib/svg_pathify.rb
|
21
|
+
- lib/svg_pathify/to_short_f.rb
|
22
|
+
- lib/svg_pathify/shapes/rect.rb
|
23
|
+
- lib/svg_pathify/shapes/polygon.rb
|
24
|
+
- lib/svg_pathify/shapes/line.rb
|
25
|
+
- lib/svg_pathify/shapes/circle.rb
|
26
|
+
- lib/svg_pathify/shapes/ellipse.rb
|
27
|
+
- lib/svg_pathify/shape.rb
|
28
|
+
- test/svg_pathify_test.rb
|
29
|
+
homepage: https://github.com/qhwa/svg_pathify
|
30
|
+
licenses:
|
31
|
+
- MIT
|
32
|
+
metadata: {}
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubyforge_project:
|
49
|
+
rubygems_version: 2.0.3
|
50
|
+
signing_key:
|
51
|
+
specification_version: 4
|
52
|
+
summary: turn svg shape tags into <path> tag.
|
53
|
+
test_files: []
|