ソフトウェア/tchart.rb の履歴(No.7)
更新- テキストファイルのソースを与えてタイミング図を作成するスクリプトです
- 使用例
- こちらのアドレスで試すことができます
- タイミング記述テキストの文法
- タイミング定義の文法と用例
- _ と ~ で 0 と 1 を表します。
- - がハイインピーダンス状態です。
- バス信号や不定値を表すのに = を使えます。
- X で値の切り替えを表せます。
- 信号定義に文字列を書き入れることができます。
- ? を一文字だけ書くと不定値を表すために色が付きます。
- : を入れると空白を入れ、途切れさせることができます。
- 不定値部分を表すのに、/ \ * が使えます。
- | を入れるとグリッド線を引けます。
- [ ] でくくるとハイライトできます。
- 全ての組み合わせを試してみます
- 不定値の塗り分けをテスト。
- 遷移の傾きをなくすには @w_transient 0 とします
- svg の特殊文字も正しくエスケープされます
- 生成された svg には変換元のソースコードが埋め込まれます。
- 設定値
- ソースファイル
- ちょっと疑問
- もしかして、javascript で作った方が良かったんじゃないだろうか・・・
- コメント・質問
テキストファイルのソースを与えてタイミング図を作成するスクリプトです†
"Timing chart formatter by kumagai"
http://www.mech.tohoku-gakuin.ac.jp/rde/contents/library/tchart/indexframe.html
を参考にして、svg を出力するように ruby で作りました。
svg の使い方はこちらのサイトを参考にさせていただきました。
http://www.h2.dion.ne.jp/~defghi/svgMemo/svgMemo.htm
かなり走り書き的なところがありますが、ご容赦下さい。
使用例†
次のようなテキストから、
# AXI4 fundamental protocol clock _~_~_~_~_~_~_~_~_~_~_ data =?====X=DATA========X=?==== valid _____~~~~~~~~~~______ ready _____________[~~]______
このようなタイミング図を SVG として出力します。
&tchart(
# AXI4 fundamental protocol clock _~_~_~_~_~_~_~_~_~_~_ data =?====X=DATA========X=?==== valid ~~~~~~~~~~_ ready ________[~~]_ );
こちらのアドレスで試すことができます†
オンラインで変換結果を得られます(svn形式 or png形式):
http://output.jsbin.com/xakesiquga
こちらは javascript で書かれており、サーバーに負荷は掛かりませんので、 そのままタイミングチャートの作成用として、ご利用いただけます。
タイミング記述テキストの文法†
# から始まる行はコメント行です†
# This line will not appear in the chart clk _~_~_~_~_~ signal ___~~~~___
&tchart(
# This line will not appear in the chart
clk _~_~_~_~_
signal ~~~~
);
@ から始まる行で設定を変更できます†
形式は次の通りです。
@[設定値の名称][スペース][設定値]
@signal_style stroke-linecap="round" stroke-width="2" stroke="green" fill="none" clk _~_~_~_~_~ signal ___~~~~___
&tchart(
@signal_style stroke-linecap="round" stroke-width="2" stroke="green" fill="none"
clk _~_~_~_~_
signal ~~~~
);
% から始まる行で自由な位置に文字列を追加できます†
与えるパラメータは、次の通りです。
%[x座標][スペース][y座標][スペース][文字列]
@margin 20 %100 -7 test! clk _~_~_~_~_~ signal ___~~~~___
&tchart(
@margin 20
%100 -7 test!
clk _~_~_~_~_
signal ~~~~
);
空行があれば1行分だけ空白が空きます†
clk1 _~_~_~_~_~ clk2 __~~__~~__ signal ___~~_____
&tchart(
clk1 _~_~_~_~_
clk2 ~~~~__
signal ~~__ );
その他の文字から始まる行が信号になります†
フォーマットは
信号名 [空白] タイミング定義
の形です。
タイミング定義の文法と用例†
_ と ~ で 0 と 1 を表します。†
- がハイインピーダンス状態です。†
clk _~_~_~_~_~_~_~_~_~ data ___~~~~__~~____~~_ enable ___~~~~~~~~~~_____ output ---~~~~__~~__-----
&tchart(
clk _~_~_~_~_~_~_~_~_
data _~~~~~~____~~_
enable ~~~~~~~~~~__
output ---~~~~~~-----
);
バス信号や不定値を表すのに = を使えます。†
X で値の切り替えを表せます。†
X は時間が進みます。イメージ的には X= のように働きます。
clk _~_~_~_~_~ data =X=X=X=X=X
&tchart(
clk _~_~_~_~_
data =X=X=X=X=X
);
信号定義に文字列を書き入れることができます。†
? を一文字だけ書くと不定値を表すために色が付きます。†
文字列を書いても時間は進みません。
clk _~_~_~_~_~_~_~_~_~ enable ___~~~~~~~~~~_____ output ---=D0=X=D1X=D2X=D3X=D4-----
&tchart(
clk _~_~_~_~_~_~_~_~_
enable ~~~~~~~~~~__
output ---=D0=X=D1X=D2X=D3X=D4-----
);
clk _~_~_~_~_~_~ data =?==XDATA=====X=?= valid ___~~~~~~___
&tchart(
clk _~_~_~_~_~_
data =?==XDATA=====X=?=
valid ~~~~~~
);
: を入れると空白を入れ、途切れさせることができます。†
clk _~_~_~_:...:~_~_~_~_~ data ___~~~~:...:~~____~~_
&tchart(
clk _~_~_~_:...:~_~_~_~_
data ~~~~:...:~~_~~_
);
不定値部分を表すのに、/ \ * が使えます。†
clk _~_~_~_~_~_~_~ rising ___==/=/=~~~~~ falling ~~~==\=\=_____ transition ___=D0=*=D1*=D2*=D3___
&tchart(
clk _~_~_~_~_~_~_
rising ___==/=/=~~~~
falling ~~~==\=\=_____
transition =D0=*=D1*=D2*=D3
);
| を入れるとグリッド線を引けます。†
[ ] でくくるとハイライトできます。†
clk _~_~_~_~_~_~_~_~_~ data ___~~~~~~~~|____~~_ enable ___[~~~~~~~~~~]_____ output ---~~~~~~~~__-----
&tchart(
clk _~_~_~_~_~_~_~_~_
data ~~~~~~~~|_~~_
enable [~~~~~~~~~~]__
output ---~~~~~~~~__-----
);
全ての組み合わせを試してみます†
# :-~_=/\X* 0 _~_~_~_~_~_~_[~_~_]~_ 1 :::-:~:_:=:/:\:X:*: 2 -:---~-_-=-/-\-X-*- 3 ~:~-~~~_~=~/~\~X~*~ 4 _:_-_~___=_/_\_X_*_ 5 =:=-=|~=_===/=\=X=*= 6 /:/-/~/_/=///\/X/*/ 7 \:\-\~\_\=\/\\\X\*\ 8 X:X-X~X_X=X/X\XXX*X 9 *:*-*~*_*=*/*\*X***
&tchart(
# :-~_=/\X* 0 _~_~_~_~_~_~_[~_~_]~_
1 :::-:~:_:=:/:\:X:*:
2 -:---~-_-=-/-\-X-*-
3 ~:~-~~~_~=~/~\~X~*
4 _:_-_~___=_/_\_X_*_
5 =:=-=|~=_===/=\=X=*=
6 /:/-/~/_/=///\/X/*/
7 \:\-\~\_\=\/\\\X\*\
8 X:X-X~X_X=X/X\XXX*X
9 *:*-*~*_*=*/*\*X***
);
不定値の塗り分けをテスト。†
@h_line 30 @h_skip 20 @w_transient 5 @w_caption 60 test =/=?\=\=?/=X=?X=*?=*=X=?-=?= =?X
&tchart( @h_line 30 @h_skip 20 @w_transient 5 @w_caption 60 test =/=?\=\=?/=X=?X=*?=*=X=?-=?= =?X );
遷移の傾きをなくすには @w_transient 0 とします†
@w_transient 0 clk _~_~_~_~_~_~_~ data ___|~~~~|_______
&tchart(
@w_transient 0
clk _~_~_~_~_~_~_
data |~~~~|____
);
svg の特殊文字も正しくエスケープされます†
clk _~_~_~_~_~_~_~ data ---|===<D1>=X=<D2>==|---
&tchart(
clk _~_~_~_~_~_~_
data ---|===<D1>=X=<D2>==|---
);
生成された svg には変換元のソースコードが埋め込まれます。†
下記の CDATA の部分です。ソースコードに CDATA の終了を示す ]]> が現れる場合には、 ]]> にエンコードされます。
LANG:xml
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="240pt" height="60pt" viewBox="-10 -10 220 40" version="1.1">
<![CDATA[
clk _~_~_~_~_~_~_~
data ---|===<D1>=X=<D2>==|---
]]>
<g>
<text x="35" y="8.5" text-anchor="end" font-size="10" fill="black" font-family="Helvetica">clk</text>
<path stroke-linecap="round" stroke-width="0.6" stroke="black" fill="none" d="M42,10H52L54,0H64L66,10H76L78,0H88L90,10H100L102,0H112L114,10H124L126,0H136L138,10H148L150,0H160L162,10H172L174,0H184L186,10H196L198,0H208" />
<text x="35" y="28.5" text-anchor="end" font-size="10" fill="black" font-family="Helvetica">data</text>
<text x="101.0" y="28.5" text-anchor="middle" font-size="10" fill="black" font-family="Helvetica"><D1></text>
<text x="149.0" y="28.5" text-anchor="middle" font-size="10" fill="black" font-family="Helvetica"><D2></text><path stroke-linecap="round" stroke-width="0.6" stroke="black" fill="none" d="M42,25H52H54H64H66H76L78,20H88H90H100H102H112H114H124L126,30H136H138H148H150H160H162H172L174,25H184H186H196H198H208M76,25L78,30H88H90H100H102H112H114H124L126,20H136H138H148H150H160H162H172L174,25" />
<path d="M77,-10V40" stroke-linecap="round" stroke-width="0.6" stroke="red" fill="none" />
<path d="M173,-10V40" stroke-linecap="round" stroke-width="0.6" stroke="red" fill="none" />
</g>
</svg>
設定値†
scale (= 1.0)†
図のサイズを拡大・縮小します。 複数指定した場合、最後の値だけが意味を持ちます。
@scale 1.4 clk _~_~_~_~_~_~_~_~ data ==?=X=D0X=D1X=D2X=D3X=?===
&tchart(
@scale 1.4
clk _~_~_~_~_~_~_~_
data ==?=X=D0X=D1X=D2X=D3X=?===
);
@scale 0.7 clk _~_~_~_~_~_~_~_~ data ==?=X=D0X=D1X=D2X=D3X=?===
&tchart(
@scale 0.7
clk _~_~_~_~_~_~_~_
data ==?=X=D0X=D1X=D2X=D3X=?===
);
margin (= 10)†
チャートの周囲の余白の幅を指定します。
w_caption (= 40)†
信号名称部分の幅を指定します。
long_signal_name _~~~~__~~~~______~~___
&tchart( long_signal_name _~~~~~~~~_~~ );
@w_caption 100 long_signal_name _~~~~__~~~~______~~___
&tchart( @w_caption 100 long_signal_name _~~~~~~~~_~~ );
w_hold (= 10)†
信号の単位時間から遷移時間を引いた部分の幅を指定します。 途中で変更すれば異なるクロックドメインを表したりできます。
@w_hold 10 clock _~_~_~_~_~_~_~_~_~_~_~ @w_hold 22 clock ~_~_~_~_~_~ @w_hold 16 clock _~_~_~_~_~_~_~_
&tchart(
@w_hold 10
clock _~_~_~_~_~_~_~_~_~_~_
@w_hold 22
clock ~_~_~_~_~_
@w_hold 16
clock _~_~_~_~_~_~_~_
);
w_transient (= 2)†
信号の遷移時間の幅を指定します。 ゼロを指定すると、遷移のエッジは垂直になります。
@w_transient 0 clock _~_~_~_~_~_~_~_~_~_~_~ @w_transient 2 clock _~_~_~_~_~_~_~_~_~_~_~ @w_transient 4 clock _~_~_~_~_~_~_~_~_~_~_~
&tchart(
@w_transient 0
clock _~_~_~_~_~_~_~_~_~_~_
@w_transient 2
clock _~_~_~_~_~_~_~_~_~_~_
@w_transient 4
clock _~_~_~_~_~_~_~_~_~_~_
);
h_line (= 10)†
1行の高さを指定します。信号名のフォントサイズもこの値に等しくなります。
@h_line 10 clock _~_~_~_~_~_~_~_~_~_~_~ @h_line 16 clock _~_~_~_~_~_~_~_~_~_~_~
&tchart(
@h_line 10
clock _~_~_~_~_~_~_~_~_~_~_
@h_line 16
clock _~_~_~_~_~_~_~_~_~_~_
);
h_space (= 10)†
行間のスペースを指定します。
clock _~_~_~_~_~_~_~_~_~_~_~ data1 _~~~~__~~~~______~~___ @h_space 20 data2 _~~~~__~~~~______~~___ data3 _~~~~__~~~~______~~___
&tchart(
clock _~_~_~_~_~_~_~_~_~_~_
data1 _~~~~~~~~_~~
@h_space 20
data2 _~~~~~~~~_~~
data3 _~~~~~~~~_~~
);
signal_style†
信号線のスタイルを svg の path の属性値の形で与えます。 規定値は次の通りです。
stroke-linecap="round" stroke-width="0.6" stroke="black" fill="none"
data1 _~~~~__~~~~______~~___ @signal_style stroke-linecap="round" stroke-width="2" stroke="green" fill="none" data2 _~~~~__~~~~______~~___
&tchart( data1 _~~~~~~~~_~~ @signal_style stroke-linecap="round" stroke-width="2" stroke="green" fill="none" data2 _~~~~~~~~_~~ );
grid_style†
グリッド線のスタイルを svg の path の属性値の形で与えます。 規定値は次の通りです。
stroke-linecap="round" stroke-width="0.6" stroke="red" fill="none"
@grid_style stroke-linecap="round" stroke-width="0.6" stroke="black" fill="none" data1 _~~~~__|~~~~______~~___ @grid_style stroke-linecap="round" stroke-width="0.6" stroke="#0CC" fill="none" data2 _~~~~__~~~~______|~~___
&tchart( @grid_style stroke-linecap="round" stroke-width="0.6" stroke="black" fill="none" data1 _~~~~|~~~~_~~ @grid_style stroke-linecap="round" stroke-width="0.6" stroke="#0CC" fill="none" data2 _~~~~~~~~_|~~ );
highlight_style†
ハイライト部分のスタイルを指定します。
規定値は次の通りです。
stroke="none" fill="#ff8"
data1 _~~~~__[~~~~]______~~___ @highlight_style stroke="green" fill="#8f8" stroke-width="1" data2 _~~~~__~~~~______[~~]___
&tchart( data1 _~~~~[~~~~]_~~ @highlight_style stroke="green" fill="#8f8" stroke-width="1" data2 _~~~~~~~~_[~~] );
notcare_style†
不定値部分のスタイルを指定します。
fill="#ccc"
clk _~_~_~_~_~_~_~_~_~_~_~ data1 ====?=*========*=?====== @notcare_style stroke="none" fill="#8f8" data1 ====?=*========*=?======
&tchart(
clk _~_~_~_~_~_~_~_~_~_~_
data1 ====?=*========*=?======
@notcare_style stroke="none" fill="#8f8"
data1 ====?=*========*=?======
);
caption_font†
信号名のフォントを指定します。
規定値は次の通りです。
fill="black" font-family="Helvetica"
clk _~_~_~_~_~_~_~_~_~_~_~ @caption_font fill="red" font-family="Helvetica" @signal_style stroke="red" fill="none" data _~~~~______~~____~~~~~
&tchart(
clk _~_~_~_~_~_~_~_~_~_~_
@caption_font fill="red" font-family="Helvetica"
@signal_style stroke="red" fill="none"
data _~~~~___~~_~~~~
);
signal_font†
信号部分で用いるフォントを指定します。
規定値は次の通りです。
fill="black" font-family="Helvetica"
clk _~_~_~_~_~_~_~_~ @signal_font fill="red" font-family="Helvetica" data ==?=X=D0X=D1X=D2X=D3X=?===
&tchart(
clk _~_~_~_~_~_~_~_
@signal_font fill="red" font-family="Helvetica"
data ==?=X=D0X=D1X=D2X=D3X=?===
);
rotate (= 0)†
未実装
ソースファイル†
いやほんと、走り書きですみません。
LANGUAGE:ruby(linenumber)
#!/usr/bin/ruby
#### tchart.rb by osamu@big.jp
#
# "Timing chart formatter by kumagai"
# http://www.mech.tohoku-gakuin.ac.jp/rde/contents/library/tchart/indexframe.html
#
# を参考に、svg を出力するようにしたものです
#
# かなり走り書き的なところがありますが、ご容赦下さい。
#
#####################################################################
# default config
conf = {
scale: 1.0,
margin: 10,
w_caption: 40,
w_hold: 10,
w_transient: 2,
h_line: 10,
h_space: 10,
signal_style: 'stroke-linecap="round" stroke-width="0.6" stroke="black" fill="none"',
grid_style: 'stroke-linecap="round" stroke-width="0.6" stroke="red" fill="none"',
highlight_style:'stroke="none" fill="#ff8"',
notcare_style: 'fill="#ccc"',
rotate: 0,
caption_font: 'fill="black" font-family="Helvetica"',
signal_font: 'fill="black" font-family="Helvetica"'
}
#####################################################################
class Line
class SubLine
def initialize(x,y)
@points = [[x,y]]
end
def accepts?(x,y)
@points.last == [x,y]
end
def add(x,y)
@points << [x,y]
end
def path
result = ''
last = nil
@points.each do |p|
if last
if last==p
next
elsif last[0]==p[0]
result += 'V%g' % p[1]
elsif last[1]==p[1]
result += 'H%g' % p[0]
else
result += "L%g,%g" % p
end
else
result = "M%g,%g" % p
end
last = p
end
result
end
end
def initialize(style)
@lines = []
@style = style
end
def draw(x1, y1, x2, y2)
unless line = @lines.find {|line| line.accepts?(x1, y1) }
line = SubLine.new(x1, y1)
@lines << line
end
line.add(x2, y2)
end
def svg
path = @lines.map{|line| line.path }.join('')
%Q[<path #{@style} d="#{path}" />]
end
end
class Timeline
# : - ~ _ =
@@transitions = [
' ', # :
' - 1 4 14', # -
' 2 ~ / ~/', # ~
' 3 ` _ _`', # _
' 23`~/_= ', # =
' 23`~/_=/', # /
' 23`~/_=`', # \
' 23`~/_X ', # X
' 23`~/_=X', # *
]
@@transition_lines = {
' ' => [],
'~' => [[1,1]],
'_' => [[0,0]],
'=' => [[1,1],[0,0]],
'X' => [[1,0],[0,1]],
'`' => [[1,0]],
'/' => [[0,1]],
'1' => [[1,0.5]],
'2' => [[0.5,1]],
'3' => [[0.5,0]],
'4' => [[0,0.5]],
'-' => [[0.5,0.5]],
}
# : - ~ _ =
@@state_lines = [[],[0.5],[1],[0],[0,1]]
#
@@codes = ':-~_=/\\X*'
@@grids = []
def self.grids
@@grids
end
@@highlight = []
def self.highlight
@@highlight
end
def initialize(conf, y)
@line = Line.new(conf[:signal_style])
@current = 0
@conf = conf
@x = conf[:w_caption]
@y = y
@crosses = []
@strings = []
end
def y(s)
@y + (1-s) * @conf[:h_line]
end
def y0
@y + @conf[:h_line]
end
def y1
@y
end
def yz
@y + @conf[:h_line]/2.0
end
def x
@x
end
def xh
@x + @conf[:w_transient]/2.0
end
def xt
@x + @conf[:w_transient]
end
def xr
@x + @conf[:w_transient] + @conf[:w_hold]
end
def draw_transition_sub(c)
crosses = ''
@@transition_lines[c].each do |line|
@line.draw(x, y(line[0]), xt, y(line[1]))
crosses += c if line[0] != line[1]
end
crosses
end
def draw_transition(s)
crosses = ''
@@transitions[s][2*@current,2].each_char do |c|
crosses += draw_transition_sub(c)
end
crosses
end
def draw_state(s)
@@state_lines[s].each do |line|
@line.draw(xt, y(line), xr, y(line))
end
end
def add(c)
s = @@codes.index(c)
crosses = draw_transition(s)
s = 4 if s > 4
draw_state(s)
@crosses << [x, crosses] if crosses!=''
if (@current == 0 and s != 0) or (@current != 0 and s == 0)
@crosses << [x, '|']
end
@current = s
@x = xr
end
def add_string(s)
@strings << [@crosses.count, s]
end
def parse(line)
while line != ''
if line.sub!(/^\s+/, '')
elsif line.sub!(/^\|/, '')
@@grids << xh
elsif line.sub!(/^\[/, '')
if @@highlight.last==nil or @@highlight.last.is_a?(Array)
@@highlight << xh
end
elsif line.sub!(/^\]/, '')
if @@highlight.last.is_a?(Numeric)
@@highlight[-1] = [@@highlight.last, xh]
end
elsif line.sub!(/^([:\-~_=\/\\X*])/, '')
add($1)
elsif line.sub!(/"(([^"]|"")+)"/, '')
add_string($1.strip)
elsif line.sub!(/([^:\-~_=\/\\X*]+)/, '')
add_string($1.strip)
end
end
end
def string2svg
@crosses << [x,'|']
@strings.map do |string|
x1 = @crosses[string[0]-1][0]
x1t = x1 + @conf[:w_transient]
x1h = x1 + @conf[:w_transient]/2.0
x1r = x1t + @conf[:w_hold]
x2 = @crosses[string[0] ][0]
x2t = x2 + @conf[:w_transient]
x2h = x2 + @conf[:w_transient]/2.0
x2r = x2t + @conf[:w_hold]
#
sanitized = string[1].gsub(/</, '<').gsub(/>/, '>').gsub(/"/, '"')
svg = %Q(<text x="#{(x1h + x2h)/2.0}" y="#{y0-1.5}" text-anchor="middle" font-size="#{@conf[:h_line]}" #{@conf[:signal_font]}>#{sanitized}</text>)
if string[1] == '?'
line = "M#{x1t},#{y1}H#{x2}"
case @crosses[string[0]][1]
when '|'
;
when 'XX'
line += "L#{x2h},#{yz}"
when '/'
line += "H#{x2t}"
when '`'
line += "L#{x2t},#{y0}"
when '23'
line += "H#{x2t}L#{x2},#{yz}L#{x2t},#{y0}"
when '14'
line += "L#{x2t},#{yz}"
when '1'
line += "L#{x2t},#{yz}V#{y0}"
when '2'
line += "H#{x2t}L#{x2},#{yz}"
when '3'
line += "V#{yz}L#{x2t},#{y0}"
when '4'
line += "H#{x2t}V#{yz}"
end
line += "L#{x2},#{y0}H#{x1t}"
case @crosses[string[0]-1][1]
when '|'
;
when 'XX'
line += "L#{x1h},#{yz}"
when '/'
line += "H#{x1}"
when '`'
line += "L#{x1},#{y1}"
when '23'
line += "L#{x1},#{yz}"
when '14'
line += "H#{x1}L#{x1t},#{yz}L#{x1},#{y1}"
when '1'
line += "V#{yz}L#{x1},#{y1}"
when '2'
line += "H#{x1}V#{yz}"
when '3'
line += "L#{x1},#{yz}V{y1}"
when '4'
line += "H#{x1}L#{xt},#{yz}"
end
line += "Z"
svg = %Q(\n<path stroke="none" d="#{line}" #{@conf[:notcare_style]}/>) + svg
end
svg
end.join("\n")
end
def svg
string2svg + @line.svg
end
end
def caption2svg(conf, y, caption)
sanitized = caption.gsub(/</, '<').gsub(/>/, '>').gsub(/"/, '"')
%Q(<text x="#{conf[:w_caption]-5}" y="#{y+conf[:h_line]-1.5}" text-anchor="end" font-size="#{conf[:h_line]}" #{conf[:caption_font]}>#{sanitized}</text>)
end
#####################################################################
svg = []
y = -1
x_max = 0
lines = readlines
lines.shift while lines[0] =~ /^\s*$/
lines.pop while lines.last =~ /^\s*$/
lines.each do |line|
next if line =~ /^\#/
if line =~ /^@/ #### configuration
if line !~ /^@([^\s]+)[\s]+([^\s].*)$/
STDERR.puts "Illegal Line: #{line}"
next
end
if conf[$1.to_sym].is_a?(Numeric)
conf[$1.to_sym] = $2.to_f
else
conf[$1.to_sym] = $2
end
next
end
if line =~ /^%/ #### free string
if line !~ /^%([\d\.-]+)[\s]+([\d\.-]+)[\s]+([^\s].*)$/
STDERR.puts "Illegal Line: #{line}"
next
end
svg << %Q(<text x="#{$1}" y="#{$2}" text-anchor="middle" font-size="#{conf[:h_line]}" #{conf[:signal_font]}>#{$3}</text>)
next
end
if y < 0
y = 0
else
y += conf[:h_space]
end
line.sub!(/\s*$/, '')
next if line == ''
if line !~ /^([^\s]+)[\s]+([^\s].*)$/
STDERR.puts "Illegal Line: #{line}"
next
end
caption_s = $1
timeline_s = $2
svg << caption2svg(conf, y, caption_s)
timeline = Timeline.new(conf, y)
timeline.parse(timeline_s)
x_max = timeline.xr if x_max < timeline.xr
svg << timeline.svg
y += conf[:h_line]
end
m = conf[:margin]
w = "%g" % ((x_max + 2*m) * conf[:scale])
h = "%g" % ((y + 2*m) * conf[:scale])
l = "%g" % (-m)
t = "%g" % (-m)
r = "%g" % (x_max+2*m)
b = "%g" % (y +2*m)
Timeline.grids.each do |g|
x = "%g" % g
svg << %Q(<path d="M#{x},#{'%g' % (-m/2)}V#{'%g' % (y+m/2)}" #{conf[:grid_style]} />)
end
Timeline.highlight.each do |h|
if h.is_a?(Array)
x1 = "%g" % h[0]
x2 = "%g" % h[1]
svg.unshift %Q(<path d="M#{x1},#{'%g' % (-m/2)}V#{'%g' % (y+m/2)}H#{x2}V#{'%g' % (-m/2)}Z" #{conf[:highlight_style]} />)
end
end
print <<SVG
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="#{w}pt" height="#{h}pt" viewBox="#{l} #{t} #{r} #{b}" version="1.1">
<![CDATA[
#{lines.join("\n").gsub(/\]\]\>/, ']]>')}
]]>
<g>
#{svg.join("\n")}
</g>
</svg>
SVG
ちょっと疑問†
ハイインピーダンスからの遷移の書き方はこれで良いんだろうか?
他と傾きが違ってしまうけれど・・・
@h_line 30 @h_skip 20 @w_transient 8 @w_caption 100 test1 ___|~~~|___|==|X=|X= test2 ---~~~---==--==
&tchart( @h_line 30 @h_skip 20 @w_transient 8 @w_caption 100 test1 |~~~||==|X=|X= test2 ---~~~---==--== );
もしかして、javascript で作った方が良かったんじゃないだろうか・・・†
javascript で実装すればクライアント側の処理だけで図を描画できますし、 最近はそのまま画像として保存することもできるそうで、
http://www.pori2.net/html5/Canvas/150.html
ずっと良かったのかもしれません???
確かに・・・ずっとよさそうです
http://output.jsbin.com/nirugenabu/1