prawn-svg 0.9.1.10 → 0.9.1.11
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.
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/Gemfile +14 -0
- data/Rakefile +26 -0
- data/lib/prawn/svg/element.rb +7 -2
- data/lib/prawn/svg/font.rb +7 -4
- data/lib/prawn/svg/parser.rb +12 -4
- data/lib/prawn/svg/version.rb +5 -0
- data/prawn-svg.gemspec +23 -0
- data/spec/lib/parser_spec.rb +58 -0
- data/spec/lib/path_spec.rb +38 -0
- data/spec/lib/svg_spec.rb +22 -0
- data/spec/prawn/svg/document_spec.rb +27 -0
- data/spec/prawn/svg/element_spec.rb +32 -0
- data/spec/prawn/svg/font_spec.rb +31 -0
- data/spec/prawn/svg/parser/text_spec.rb +4 -0
- data/spec/sample_output/directory +0 -0
- data/spec/sample_svg/arcs01.svg +21 -0
- data/spec/sample_svg/circle01.svg +12 -0
- data/spec/sample_svg/cubic01.svg +37 -0
- data/spec/sample_svg/cubic01a.svg +40 -0
- data/spec/sample_svg/cubic02.svg +86 -0
- data/spec/sample_svg/ellipse01.svg +17 -0
- data/spec/sample_svg/line01.svg +22 -0
- data/spec/sample_svg/maths.svg +34 -0
- data/spec/sample_svg/omnigraffle.svg +41 -0
- data/spec/sample_svg/opacity01.svg +42 -0
- data/spec/sample_svg/polygon01.svg +17 -0
- data/spec/sample_svg/polyline01.svg +18 -0
- data/spec/sample_svg/quad01.svg +28 -0
- data/spec/sample_svg/rect01.svg +12 -0
- data/spec/sample_svg/rect02.svg +16 -0
- data/spec/sample_svg/rotate_scale.svg +38 -0
- data/spec/sample_svg/scruffy_graph.svg +134 -0
- data/spec/sample_svg/triangle01.svg +12 -0
- data/spec/sample_svg/tspan01.svg +17 -0
- data/spec/sample_svg/tspan02.svg +22 -0
- data/spec/sample_svg/tspan03.svg +21 -0
- data/spec/sample_svg/use.svg +17 -0
- data/spec/spec_helper.rb +9 -0
- metadata +103 -15
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Declare your gem's dependencies in prawn-svg.gemspec.
|
4
|
+
# Bundler will treat runtime dependencies like base dependencies, and
|
5
|
+
# development dependencies will be added by default to the :development group.
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
# Declare any dependencies that are still in development here instead of in
|
9
|
+
# your gemspec. These might include edge Rails or gems from your path or
|
10
|
+
# Git. Remember to move these dependencies to your gemspec before releasing
|
11
|
+
# your gem to rubygems.org.
|
12
|
+
|
13
|
+
# To use debugger
|
14
|
+
# gem 'ruby-debug19', :require => 'ruby-debug'
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'rdoc/task'
|
7
|
+
rescue LoadError
|
8
|
+
require 'rdoc/rdoc'
|
9
|
+
require 'rake/rdoctask'
|
10
|
+
RDoc::Task = Rake::RDocTask
|
11
|
+
end
|
12
|
+
|
13
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
14
|
+
rdoc.rdoc_dir = 'rdoc'
|
15
|
+
rdoc.title = 'prawn-svg documentation'
|
16
|
+
rdoc.options << '--line-numbers'
|
17
|
+
rdoc.rdoc_files.include('README')
|
18
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rspec/core/rake_task'
|
22
|
+
|
23
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
24
|
+
end
|
25
|
+
|
26
|
+
task :default => :spec
|
data/lib/prawn/svg/element.rb
CHANGED
@@ -56,8 +56,13 @@ class Prawn::Svg::Element
|
|
56
56
|
x, y = x.split(/\s+/) if y.nil?
|
57
57
|
add_call_and_enter name, @document.distance(x), -@document.distance(y)
|
58
58
|
|
59
|
-
when 'rotate'
|
60
|
-
|
59
|
+
when 'rotate'
|
60
|
+
rotation_arguments = arguments.first.split(/\s+/)
|
61
|
+
if (rotation_arguments.length == 3)
|
62
|
+
add_call_and_enter name, -rotation_arguments.first.to_f, :origin => [@document.x(rotation_arguments[1].to_f), @document.y(rotation_arguments[2].to_f)]
|
63
|
+
else
|
64
|
+
add_call_and_enter name, -arguments.first.to_f, :origin => [0, @document.y('0')]
|
65
|
+
end
|
61
66
|
|
62
67
|
when 'scale'
|
63
68
|
args = arguments.first.split(/\s+/)
|
data/lib/prawn/svg/font.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'iconv'
|
2
|
-
|
3
1
|
class Prawn::Svg::Font
|
4
2
|
BUILT_IN_FONTS = ["Courier", "Helvetica", "Times-Roman", "Symbol", "ZapfDingbats"]
|
5
3
|
|
@@ -59,7 +57,7 @@ class Prawn::Svg::Font
|
|
59
57
|
def self.font_information(filename)
|
60
58
|
File.open(filename, "r") do |f|
|
61
59
|
x = f.read(12)
|
62
|
-
table_count = x[4] * 256 + x[5]
|
60
|
+
table_count = x[4].ord * 256 + x[5].ord
|
63
61
|
tables = f.read(table_count * 16)
|
64
62
|
|
65
63
|
offset, length = table_count.times do |index|
|
@@ -86,7 +84,12 @@ class Prawn::Svg::Font
|
|
86
84
|
field = data[offset..offset+length-1]
|
87
85
|
names[name_id] = if platform_id == 0
|
88
86
|
begin
|
89
|
-
|
87
|
+
if field.respond_to?(:encode)
|
88
|
+
field.encode(Encoding::UTF16)
|
89
|
+
else
|
90
|
+
require "iconv"
|
91
|
+
Iconv.iconv('UTF-8', 'UTF-16', field)
|
92
|
+
end
|
90
93
|
rescue
|
91
94
|
field
|
92
95
|
end
|
data/lib/prawn/svg/parser.rb
CHANGED
@@ -59,6 +59,9 @@ class Prawn::Svg::Parser
|
|
59
59
|
"rect" => %w(width height),
|
60
60
|
"path" => %w(d)
|
61
61
|
}
|
62
|
+
|
63
|
+
USE_NEW_CIRCLE_CALL = Prawn::Document.new.respond_to?(:circle)
|
64
|
+
USE_NEW_ELLIPSE_CALL = Prawn::Document.new.respond_to?(:ellipse)
|
62
65
|
|
63
66
|
def parse_element(element)
|
64
67
|
attrs = element.attributes
|
@@ -106,11 +109,16 @@ class Prawn::Svg::Parser
|
|
106
109
|
element.add_call "polygon", *points
|
107
110
|
|
108
111
|
when 'circle'
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
+
if USE_NEW_CIRCLE_CALL
|
113
|
+
element.add_call "circle",
|
114
|
+
[x(attrs['cx'] || "0"), y(attrs['cy'] || "0")], distance(attrs['r'])
|
115
|
+
else
|
116
|
+
element.add_call "circle_at",
|
117
|
+
[x(attrs['cx'] || "0"), y(attrs['cy'] || "0")], :radius => distance(attrs['r'])
|
118
|
+
end
|
119
|
+
|
112
120
|
when 'ellipse'
|
113
|
-
element.add_call "ellipse_at",
|
121
|
+
element.add_call USE_NEW_ELLIPSE_CALL ? "ellipse" : "ellipse_at",
|
114
122
|
[x(attrs['cx'] || "0"), y(attrs['cy'] || "0")], distance(attrs['rx']), distance(attrs['ry'])
|
115
123
|
|
116
124
|
when 'rect'
|
data/prawn-svg.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/prawn/svg/version', __FILE__)
|
3
|
+
|
4
|
+
spec = Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'prawn-svg'
|
6
|
+
gem.version = Prawn::Svg::VERSION
|
7
|
+
gem.summary = "SVG renderer for Prawn PDF library"
|
8
|
+
gem.description = "SVG renderer for Prawn PDF library"
|
9
|
+
gem.has_rdoc = false
|
10
|
+
gem.author = "Roger Nesbitt"
|
11
|
+
gem.email = "roger@seriousorange.com"
|
12
|
+
gem.homepage = "http://github.com/mogest/prawn-svg"
|
13
|
+
|
14
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
15
|
+
gem.files = `git ls-files`.split("\n")
|
16
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
gem.name = "prawn-svg"
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "prawn", ">= 0.8.4"
|
21
|
+
gem.add_development_dependency "rspec"
|
22
|
+
gem.add_development_dependency "rake"
|
23
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::Svg::Parser do
|
4
|
+
describe "document width and height" do
|
5
|
+
it "handles the width and height being set as a %" do
|
6
|
+
svg = <<-SVG
|
7
|
+
<svg width="50%" height="50%" version="1.1">
|
8
|
+
<line x1="10%" y1="10%" x2="90%" y2="90%" />
|
9
|
+
</svg>
|
10
|
+
SVG
|
11
|
+
|
12
|
+
document = Prawn::Svg::Document.new(svg, [2000, 2000], {})
|
13
|
+
Prawn::Svg::Parser.new(document).parse[-2][-1].should == [["line", [100.0, 900.0, 900.0, 100.0], []]]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "handles the width and height being set in inches" do
|
17
|
+
svg = <<-SVG
|
18
|
+
<svg width="10in" height="10in" version="1.1">
|
19
|
+
<line x1="1in" y1="1in" x2="9in" y2="9in" />
|
20
|
+
</svg>
|
21
|
+
SVG
|
22
|
+
|
23
|
+
document = Prawn::Svg::Document.new(svg, [2000, 2000], {})
|
24
|
+
Prawn::Svg::Parser.new(document).parse[-2][-1].should == [["line", [72.0, 720.0 - 72.0, 720.0 - 72.0, 72.0], []]]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe :parse_element do
|
29
|
+
before(:each) do
|
30
|
+
@document = Prawn::Svg::Document.new("<svg></svg>", [100, 100], {})
|
31
|
+
@parser = Prawn::Svg::Parser.new(@document)
|
32
|
+
end
|
33
|
+
|
34
|
+
def mock_element(name, attributes = {})
|
35
|
+
e = mock
|
36
|
+
e.stub!(:name).and_return(name)
|
37
|
+
e.stub!(:attributes).and_return(attributes)
|
38
|
+
|
39
|
+
Prawn::Svg::Element.new(@document, e, [], {})
|
40
|
+
end
|
41
|
+
|
42
|
+
it "ignores tags it doesn't know about" do
|
43
|
+
calls = []
|
44
|
+
@parser.send :parse_element, mock_element("unknown")
|
45
|
+
calls.should == []
|
46
|
+
@document.warnings.length.should == 1
|
47
|
+
@document.warnings.first.should include("Unknown tag")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "ignores tags that don't have all required attributes set" do
|
51
|
+
calls = []
|
52
|
+
@parser.send :parse_element, mock_element("ellipse", "rx" => "1")
|
53
|
+
calls.should == []
|
54
|
+
@document.warnings.length.should == 1
|
55
|
+
@document.warnings.first.should include("Must have attributes ry on tag ellipse")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::Svg::Parser::Path do
|
4
|
+
before :each do
|
5
|
+
@path = Prawn::Svg::Parser::Path.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "command parsing" do
|
9
|
+
it "correctly parses a valid path" do
|
10
|
+
calls = []
|
11
|
+
@path.stub!(:run_path_command) {|*args| calls << args}
|
12
|
+
@path.parse("A12.34 -56.78 89B4 5 C 6,7 T QX 0")
|
13
|
+
|
14
|
+
calls.should == [
|
15
|
+
["A", [12.34, -56.78, 89]],
|
16
|
+
["B", [4, 5]],
|
17
|
+
["C", [6, 7]],
|
18
|
+
["T", []],
|
19
|
+
["Q", []],
|
20
|
+
["X", [0]]
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "correctly parses an empty path" do
|
25
|
+
@path.should_not_receive(:run_path_command)
|
26
|
+
@path.parse("").should == []
|
27
|
+
@path.parse(" ").should == []
|
28
|
+
end
|
29
|
+
|
30
|
+
it "raises on invalid characters in the path" do
|
31
|
+
lambda {@path.parse("M 10 % 20")}.should raise_error(Prawn::Svg::Parser::Path::InvalidError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "raises on numerical data before a command letter" do
|
35
|
+
lambda {@path.parse("10 P")}.should raise_error(Prawn::Svg::Parser::Path::InvalidError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::Svg::Interface do
|
4
|
+
describe "sample file rendering" do
|
5
|
+
root = "#{File.dirname(__FILE__)}/../.."
|
6
|
+
files = Dir["#{root}/spec/sample_svg/*.svg"]
|
7
|
+
|
8
|
+
it "has at least 10 SVG sample files to test" do
|
9
|
+
files.length.should >= 10
|
10
|
+
end
|
11
|
+
|
12
|
+
files.each do |file|
|
13
|
+
it "renders the #{File.basename file} sample file without warnings or crashing" do
|
14
|
+
Prawn::Document.generate("#{root}/spec/sample_output/#{File.basename file}.pdf") do
|
15
|
+
r = svg IO.read(file), :at => [0, y], :width => 612 - 72
|
16
|
+
warnings = r[:warnings].reject {|w| w =~ /Verdana/ && w =~ /is not a known font/ }
|
17
|
+
warnings.should == []
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::Svg::Document do
|
4
|
+
before(:each) do
|
5
|
+
@document = Prawn::Svg::Document.new("<svg></svg>", [100, 100], {})
|
6
|
+
end
|
7
|
+
|
8
|
+
describe :points do
|
9
|
+
it "converts a variety of measurement units to points" do
|
10
|
+
@document.send(:points, 32).should == 32.0
|
11
|
+
@document.send(:points, 32.0).should == 32.0
|
12
|
+
@document.send(:points, "32").should == 32.0
|
13
|
+
@document.send(:points, "32unknown").should == 32.0
|
14
|
+
@document.send(:points, "32pt").should == 32.0
|
15
|
+
@document.send(:points, "32in").should == 32.0 * 72
|
16
|
+
@document.send(:points, "32ft").should == 32.0 * 72 * 12
|
17
|
+
@document.send(:points, "32mm").should be_within(0.0001).of(32 * 72 * 0.0393700787)
|
18
|
+
@document.send(:points, "32cm").should be_within(0.0001).of(32 * 72 * 0.393700787)
|
19
|
+
@document.send(:points, "32m").should be_within(0.0001).of(32 * 72 * 39.3700787)
|
20
|
+
|
21
|
+
@document.send :instance_variable_set, "@actual_width", 600
|
22
|
+
@document.send :instance_variable_set, "@actual_height", 400
|
23
|
+
@document.send(:points, "50%").should == 300
|
24
|
+
@document.send(:points, "50%", :y).should == 200
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::Svg::Element do
|
4
|
+
before :each do
|
5
|
+
e = mock
|
6
|
+
e.stub!(:attributes).and_return({})
|
7
|
+
@element = Prawn::Svg::Element.new(nil, e, [], {})
|
8
|
+
end
|
9
|
+
|
10
|
+
describe :color_to_hex do
|
11
|
+
it "converts #xxx to a hex value" do
|
12
|
+
@element.send(:color_to_hex, "#9ab").should == "99aabb"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "converts #xxxxxx to a hex value" do
|
16
|
+
@element.send(:color_to_hex, "#9ab123").should == "9ab123"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "converts an html colour name to a hex value" do
|
20
|
+
@element.send(:color_to_hex, "White").should == "ffffff"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "converts an rgb string to a hex value" do
|
24
|
+
@element.send(:color_to_hex, "rgb(16, 32, 48)").should == "102030"
|
25
|
+
@element.send(:color_to_hex, "rgb(-5, 50%, 120%)").should == "007fff"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "scans the string and finds the first colour it can parse" do
|
29
|
+
@element.send(:color_to_hex, "function(#someurl, 0) nonexistent rgb( 3 ,4,5 ) white").should == "030405"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Prawn::Svg::Font do
|
4
|
+
describe :map_font_family_to_pdf_font do
|
5
|
+
it "matches a built in font" do
|
6
|
+
Prawn::Svg::Font.map_font_family_to_pdf_font("blah, 'courier', nothing").should == 'Courier'
|
7
|
+
end
|
8
|
+
|
9
|
+
it "matches a default font" do
|
10
|
+
Prawn::Svg::Font.map_font_family_to_pdf_font("serif").should == 'Times-Roman'
|
11
|
+
Prawn::Svg::Font.map_font_family_to_pdf_font("blah, serif").should == 'Times-Roman'
|
12
|
+
Prawn::Svg::Font.map_font_family_to_pdf_font("blah, serif , test").should == 'Times-Roman'
|
13
|
+
end
|
14
|
+
|
15
|
+
if !Prawn::Svg::Font.installed_fonts.empty?
|
16
|
+
it "matches a font installed on the system" do
|
17
|
+
Prawn::Svg::Font.map_font_family_to_pdf_font("verdana, sans-serif").should == 'verdana'
|
18
|
+
Prawn::Svg::Font.map_font_family_to_pdf_font("VERDANA, sans-serif").should == 'verdana'
|
19
|
+
Prawn::Svg::Font.map_font_family_to_pdf_font("something, \"Times New Roman\", serif").should == "times new roman"
|
20
|
+
Prawn::Svg::Font.map_font_family_to_pdf_font("something, Times New Roman, serif").should == "times new roman"
|
21
|
+
end
|
22
|
+
else
|
23
|
+
it "not running font test because we couldn't find a font directory"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "returns nil if it can't find any such font" do
|
27
|
+
Prawn::Svg::Font.map_font_family_to_pdf_font("blah, thing").should be_nil
|
28
|
+
Prawn::Svg::Font.map_font_family_to_pdf_font("").should be_nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<?xml version="1.0" standalone="no"?>
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
3
|
+
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
4
|
+
<svg width="12cm" height="5.25cm" viewBox="0 0 1200 400"
|
5
|
+
xmlns="http://www.w3.org/2000/svg" version="1.1">
|
6
|
+
<title>Example arcs01 - arc commands in path data</title>
|
7
|
+
<desc>Picture of a pie chart with two pie wedges and
|
8
|
+
a picture of a line with arc blips</desc>
|
9
|
+
<rect x="1" y="1" width="1198" height="398"
|
10
|
+
fill="none" stroke="blue" stroke-width="1" />
|
11
|
+
<path d="M300,200 h-150 a150,150 0 1,0 150,-150 z"
|
12
|
+
fill="red" stroke="blue" stroke-width="5" />
|
13
|
+
<path d="M275,175 v-150 a150,150 0 0,0 -150,150 z"
|
14
|
+
fill="yellow" stroke="blue" stroke-width="5" />
|
15
|
+
<path d="M600,350 l 50,-25
|
16
|
+
a25,25 -30 0,1 50,-25 l 50,-25
|
17
|
+
a25,50 -30 0,1 50,-25 l 50,-25
|
18
|
+
a25,75 -30 0,1 50,-25 l 50,-25
|
19
|
+
a25,100 -30 0,1 50,-25 l 50,-25"
|
20
|
+
fill="none" stroke="red" stroke-width="5" />
|
21
|
+
</svg>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<?xml version="1.0" standalone="no"?>
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
3
|
+
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
4
|
+
<svg width="12cm" height="4cm" viewBox="0 0 1200 400"
|
5
|
+
xmlns="http://www.w3.org/2000/svg" version="1.1">
|
6
|
+
<desc>Example circle01 - circle filled with red and stroked with blue</desc>
|
7
|
+
<!-- Show outline of canvas using 'rect' element -->
|
8
|
+
<rect x="1" y="1" width="1198" height="398"
|
9
|
+
fill="none" stroke="blue" stroke-width="2"/>
|
10
|
+
<circle cx="600" cy="200" r="100"
|
11
|
+
fill="red" stroke="blue" stroke-width="10" />
|
12
|
+
</svg>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<?xml version="1.0" standalone="no"?>
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
3
|
+
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
4
|
+
<svg width="5cm" height="4cm" viewBox="0 0 500 400"
|
5
|
+
xmlns="http://www.w3.org/2000/svg" version="1.1">
|
6
|
+
<title>Example cubic01- cubic Bézier commands in path data</title>
|
7
|
+
<desc>Picture showing a simple example of path data
|
8
|
+
using both a "C" and an "S" command,
|
9
|
+
along with annotations showing the control points
|
10
|
+
and end points</desc>
|
11
|
+
<style type="text/css"><![CDATA[
|
12
|
+
.Border { fill:none; stroke:blue; stroke-width:1 }
|
13
|
+
.Connect { fill:none; stroke:#888888; stroke-width:2 }
|
14
|
+
.SamplePath { fill:none; stroke:red; stroke-width:5 }
|
15
|
+
.EndPoint { fill:none; stroke:#888888; stroke-width:2 }
|
16
|
+
.CtlPoint { fill:#888888; stroke:none }
|
17
|
+
.AutoCtlPoint { fill:none; stroke:blue; stroke-width:4 }
|
18
|
+
.Label { font-size:22; font-family:Verdana }
|
19
|
+
]]></style>
|
20
|
+
<rect class="Border" x="1" y="1" width="498" height="398" />
|
21
|
+
<polyline class="Connect" points="100,200 100,100" />
|
22
|
+
<polyline class="Connect" points="250,100 250,200" />
|
23
|
+
<polyline class="Connect" points="250,200 250,300" />
|
24
|
+
<polyline class="Connect" points="400,300 400,200" />
|
25
|
+
<path style=" fill:none; stroke:red; stroke-width:5" d="M100,200 C100,100 250,100 250,200
|
26
|
+
S400,300 400,200" />
|
27
|
+
<circle class="EndPoint" cx="100" cy="200" r="10" />
|
28
|
+
<circle class="EndPoint" cx="250" cy="200" r="10" />
|
29
|
+
<circle class="EndPoint" cx="400" cy="200" r="10" />
|
30
|
+
<circle class="CtlPoint" cx="100" cy="100" r="10" />
|
31
|
+
<circle class="CtlPoint" cx="250" cy="100" r="10" />
|
32
|
+
<circle class="CtlPoint" cx="400" cy="300" r="10" />
|
33
|
+
<circle class="AutoCtlPoint" cx="250" cy="300" r="9" />
|
34
|
+
<text class="Label" x="25" y="70">M100,200 C100,100 250,100 250,200</text>
|
35
|
+
<text class="Label" x="325" y="350"
|
36
|
+
style="text-anchor:middle">S400,300 400,200</text>
|
37
|
+
</svg>
|