一日のチャート

Railsのアップデートをしたので、カテゴリを変更しておこう。

 
さて相変わらずのRadRails魔改造ネタなんだけど「日付単位ではなくて時間単位で表示させたい」という欲望に駆られたので試してみた。
すんげー苦労したさ。時間のプロットが。

コントローラ
  #1日のサポートのガントチャートを作ってみる
  def daygantt
    @day_gantt = find_search
    #requestがゲットなら、パラメータをセットする。
    if request.get?
      if params[:page].nil?
        @day_gantt.empty_daygantt!
        @day_gantt.select_day = Date.parse(params[:select_day]) unless params[:select_day].nil?
      end
    else
      @day_gantt.set_daygantt_params(params)
    end
    
    params[:page] = 1 if params[:page].nil?
    
    @year_from = @day_gantt.select_day.to_date.year
    @month_from = @day_gantt.select_day.to_date.month
    @day_from = @day_gantt.select_day.to_date.day
    
    @page_title = @year_from.to_s + "年" + @month_from.to_s + "月" + @day_from.to_s + "日のチャート"
    
    #時間範囲を指定、8:00から22:00まで
    @time_from = Time.mktime(@year_from,@month_from,@day_from,8,0)
    @time_to = Time.mktime(@year_from,@month_from,@day_from,22,0)
    
    @events = []
    @events += Request.find(:all,
    :conditions =>["started >= ? AND responded <= ?", @time_from, @time_to], 
       :order=>'requested DESC'
    )
    @events.sort! {|x,y| x.responded <=> y.responded}
  end

  private
  def find_search
    session[:patrol_cond] ||= PatrolCond.new
  end

Zoomは面倒だったので止めた。簡単に追加できると思うけど。
テーブルには「start」が始まり、「responded」が終わりといった感じです。
 

モデル
class PatrolCond < Cond
#daygantt
  attr_accessor :select_day    
  
#daygantt用
  def empty_daygantt!
    @select_day = Date.today
  end

#daygantt用  
  def set_daygantt_params(params)
    @select_day = params[:day_gantt][:select_day]
  end

初期化と検索後にテキストボックスにパラメータを残す為のおまじない。
 

ビュー

最初は年月日なセレクトボックスを作ってみたけど、操作性が悪かったのでcalendar date selectを使うことにした。

<%- content_for :html_header do -%>
  <%= stylesheet_link_tag 'patrol_calendar' %>
  <%= calendar_date_select_includes %>
<script type="text/javascript">
  _translations = {
    "OK": "OK",
    "Now": "現在",
    "Today": "今日" 
  }
  Date.weekdays = $w("日 月 火 水 木 金 土");
  Date.months = $w("1 2 3 4 5 6 7 8 9 10 11 12" );
</script>
<%- end -%>

<%
subject_width = 200
header_heigth = 18

headers_height = header_heigth*3

time_to_from = (@time_to - @time_from)/36

chk_hour = @time_to.hour - @time_from.hour + 1
chk_min = ((@time_to - @time_from)/600).to_i
g_width = time_to_from/10 * chk_hour + chk_min

g_height = [(20 * @events.length + 6)+50, 206].max
t_height = g_height + headers_height
%>

<h2><%= @page_title %></h2>

<% form_tag do %>
<table width="100%">
<tr>
<td align="left">
	<%= calendar_date_select(:day_gantt, :select_day) %>
    <%= submit_tag "変更", :class => "button-small" %>    
</td>
<td><%= @time_from.to_s(:jp_date) %></td>
</tr>
</table>
<% end %>

<table width="100%" style="border:1; border-collapse: collapse;">
<tr>
<td style="width:<%= subject_width %>px;">

<div style="position:relative;
	height:<%= t_height + 24 %>px;width:<%= subject_width + 1 %>px;">
<div style="right:-2px;width:<%= subject_width %>px;
	height:<%= headers_height %>px;background: #eee;" class="gantt_hdr"></div>
<div style="right:-2px;width:<%= subject_width %>px;
	height:<%= t_height %>px;border-left: 1px solid #c0c0c0;overflow:hidden;" class="gantt_hdr"></div>
<%
#
# Tasks subjects
#
top = headers_height + 8
@events.each do |i| %>
    <div style="position: absolute;line-height:1.2em;
		height:16px;top:<%= top %>px;left:4px;overflow:hidden;"><small>    
		<%= link_to h(truncate(i.member_name, 20)), :controller => 'support/response', :action=>'new', :id=>i.sup_request_id %> 	
  	</small></div>
    <% top = top + 20
end %>
</div>
</td>
<td>

<div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;">
<div style="width:<%= g_width-1 %>px;height:<%= headers_height %>px;
	background: #eee;" class="gantt_hdr">&nbsp;</div>
<%
#
# Months headers
#
	left = 0
	height = header_heigth
	width = time_to_from - 1
%>
	<div style="left:<%= left %>px;width:<%= g_width %>px;height:<%= height %>px;"
		 class="gantt_hdr">
	<%= @time_from.to_s(:jp_simple) %>&nbsp;から&nbsp;<%= @time_to.to_s(:jp_simple) %>まで</div>
	<%
	left = left + width + 1
%>

<%
#
# Weeks headers && houres
#
	left = 5
	height = header_heigth-1
	count_time = @time_from
	width = time_to_from/10

	while count_time <= @time_to
	%>
	<div style="left:<%= left %>px;top:19px;width:<%= width %>px;
			height:<%= height %>px;" class="gantt_hdr">&nbsp;<%= count_time.hour %></div>
	<%
	count_time += 60.minutes
	left=left+width+6
	end
%>

<%
#
# Times header && minitues
#
	left = 0
	height = g_height + header_heigth - 1
	count_time = @time_from
	width = time_to_from/60
	while count_time <= @time_to
	%>
	<div style="left:<%= left %>px;top:37px;width:<%= width %>px;
		height:<%= height %>px;font-size:0.7em;<%= "background:#f1f1f1;" if count_time.min == 0 %>"
		 class="gantt_hdr">
		 <%= count_time.min %>
	</div>
	<%
	count_time += 10.minutes
	left = left + width + 1	
	end
%>
	
<%
#
# Tasks
#
top = headers_height + 10
@events.each do |i| 
	i_start_time = (i.started >= @time_from ? i.started : @time_from)
	i_end_time = (i.responded <= @time_to ? i.responded : @time_to)

	chk_min = ((i_start_time - @time_from)/600).to_i
	i_left = (i_start_time - @time_from)*time_to_from/36000 + chk_min
	i_width = (i_end_time - i_start_time)*time_to_from/36000
	%>
	<div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;"
	 class="task task_todo">&nbsp;</div>

	<% # === tooltip === %>
	<div class="tooltip" style="position: absolute;top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:12px;">
	<span class="tip">
		<%= i.staff_name %><br />
		<%= h(i.member_name) %> : <%= i.status %><br />
		<%= i.started.to_s(:jp_noyear) %><br />
		<%= i.responded.to_s(:jp_noyear) %><br />
		<%= h(truncate(i.content, 256)) %>
	</span></div>

	<% top = top + 20
end %>
</div>
</td>
</tr>
</table>
  • 時間軸は決めウチなんですが、Zoomパラメータと絡めるとできるはず
  • 時間軸を縮小すると短い期間のtooltipが表示できなくなる
  • tooltipはIE6では表示されない・・・しょぼーん

 
改造なので厳密な検証とかしていませんし、なんかしらの不具合があると思います。