ソフトウェア/tchart.rb のバックアップ(No.7)

更新


公開メモ

テキストファイルのソースを与えてタイミング図を作成するスクリプトです

"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">&lt;D1&gt;</text>
<text x="149.0" y="28.5" text-anchor="middle" font-size="10" fill="black" font-family="Helvetica">&lt;D2&gt;</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(/</, '&lt;').gsub(/>/, '&gt;').gsub(/"/, '&quot;')
      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(/</, '&lt;').gsub(/>/, '&gt;').gsub(/"/, '&quot;')
  %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(/\]\]\>/, ']]&gt;')}
]]>
<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

コメント・質問





Counter: 3601 (from 2010/06/03), today: 1, yesterday: 0