テーブルの列幅を変更するjavascriptのサンプルが掲載されているページがあったのを見つけました。仕事でASP.NET AJAXを使う機会があったので、ASP.NET AJAXクライアントライブラリを使って作成してみようと思い、作ってみました。たまに変な動きをするような気がしますが、ソースを見てくれるような奇特な方いましたら、間違っているところがあればご指摘下さい。
参照元のプログラムを完璧にコピーしているわけではありません。また、少しアレンジして、縦幅も変更できるようにしています。
// サイズ変更可能スクリプト
// テーブルの行の高さ、列の幅を
// 変更します。
// tableは先頭にヘッダが定義されている
// 前提で作成しています
// 前提: ASP.NET AJAX Client Library
Type.registerNamespace("ComponentGeek");
// define ComponentGeek.TableResizer Start -->
ComponentGeek.TableResizer = function ComponentGeek$TableResizer(){
ComponentGeek.TableResizer.initializeBase(this);
this._tableId; // 対象のテーブルID
this._target; // サイズ変更対象セル
this._startX; // 幅変更開始X座標
this._endX; // 幅変更終了X座標
this._startY; // 高さ変更開始Y座標
this._endY; // 高さ変更開始X座標
this._xResizing = false; // 幅変更中フラグ
this._yResizing = false; // 高さ変更中フラグ
this._resizeThreashold = 8; // 最小変更幅
this._edgeThreshold = 8; // 幅,高さ変更カーソル表示閾値
this._sizeThreshold = 20; // 最小列,幅高さ
this._vBarID = "vBarID"; // 変更時に表示する縦棒のID
this._hBarID = "hBarID"; // 変更時に表示する横棒のID
this._xResizeCursorVisible = false; // 幅の変更カーソル表示フラグ
this._yResizeCursorVisible = false; // 高さの変更カーソル表示フラグ
}
ComponentGeek.TableResizer.prototype = {
RegisterEvent : ComponentGeek$TableResizer$RegisterEvent,
MouseDown : ComponentGeek$TableResizer$MouseDown,
MouseUp : ComponentGeek$TableResizer$MouseUp,
MouseMove : ComponentGeek$TableResizer$MouseMove,
CreateBar : ComponentGeek$TableResizer$CreateBar,
Clear : ComponentGeek$TableResizer$Clear,
GetFirstColumn : ComponentGeek$TableResizer$GetFirstColumn
}
function ComponentGeek$TableResizer$RegisterEvent(tableId){
/// <summary>イベント登録メソッド</summary>
var self = this;
this._tableId = tableId;
var tbl = $get(tableId);
if(tbl){
$addHandler(tbl, "mousedown", function(e){ self.MouseDown(e);});
$addHandler(tbl, "mouseup", function(e){ self.MouseUp(e);});
$addHandler(tbl, "mousemove", function(e){ self.MouseMove(e);});
tbl.runtimeStyle.tableLayout = "fixed"; // リサイズ可能にする
}
this.CreateBar();
}
function ComponentGeek$TableResizer$CreateBar(){
// リサイズ時に表示する縦横バー作成
// 横幅変更バー作成
var elem = $get(this._vBarID);
if(!elem){
elem = document.createElement("span");
elem.id = this._vBarID;
elem.style.position = "absolute";
elem.style.top = "0";
elem.style.left = "0";
elem.style.height = "0";
elem.style.width = "2";
elem.style.background = "silver";
elem.style.borderLeft = "1px solid black";
elem.style.display = "none";
document.body.appendChild(elem);
}
// 縦幅変更用バー作成
elem = $get(this._hBarID);
if(!elem){
elem = document.createElement("hr");
elem.id = this._hBarID;
elem.style.position = "absolute";
elem.style.top = "0";
elem.style.left = "0";
elem.style.height = "2";
elem.style.width = "0";
elem.style.background = "silver";
elem.style.borderLeft = "1px solid black";
elem.style.display = "none";
document.body.appendChild(elem);
}
}
function ComponentGeek$TableResizer$Clear(){
// プロパティをクリア
var elem = $get(this._vBarID);
if(elem){
elem.runtimeStyle.display = "none";
}
elem = $get(this._hBarID);
if(elem){
elem.runtimeStyle.display = "none";
}
this._target = null;
this._startX = null;
this._endX = null;
this._startY = null;
this._endY = null;
this._xResizing = false;
this._yResizing = false;
}
function ComponentGeek$TableResizer$GetFirstColumn(tbl, cellIndex){
// テーブルの1行目のセルを取得する
var headerCell = tbl.rows(0).cells(cellIndex);
return headerCell;
}
function ComponentGeek$TableResizer$MouseDown(e){
// マウスダウンイベント
// 変更カーソル表示中の場合はリサイズ開始
var vBar = $get(this._vBarID);
if(!vBar) return;
var hBar = $get(this._hBarID);
if(!hBar) return;
var tbl = $get(this._tableId);
if(!tbl) return;
if(this._xResizeCursorVisible){
this._target = e.target;
this._startX = e.clientX;
this._xResizing = true;
tbl.setCapture();
vBar.runtimeStyle.top = document.body.offsetTop + tbl.parentElement.offsetTop + tbl.offsetTop;
vBar.runtimeStyle.left = e.clientX + document.documentElement.scrollLeft;
if(tbl.parentElement.offsetHeight < tbl.offsetHeight){
vBar.runtimeStyle.height = tbl.parentElement.offsetHeight;
}else{
vBar.runtimeStyle.height = tbl.offsetHeight;
}
vBar.runtimeStyle.display = "inline";
}else if(this._yResizeCursorVisible){
this._target = e.target;
this._startY = e.clientY;
this._yResizing = true;
tbl.setCapture();
hBar.runtimeStyle.top = e.clientY + document.documentElement.scrollTop;
hBar.runtimeStyle.left = tbl.parentElement.offsetLeft + document.documentElement.scrollLeft + document.body.offsetLeft;
if(tbl.parentElement.offsetWidth < tbl.offsetWidth){
hBar.runtimeStyle.width = tbl.parentElement.offsetWidth;
}else{
hBar.runtimeStyle.width = tbl.offsetWidth;
}
hBar.runtimeStyle.display = "inline";
}
}
function ComponentGeek$TableResizer$MouseMove(e){
// マウス移動イベント
// マウスが列の左端,下端に近づくとカーソル変更
if(this._xResizing || this._yResizing){
var vBar = $get(this._vBarID);
if(!vBar) return;
var hBar = $get(this._hBarID);
if(!hBar) return;
// 変更バー移動
if(this._xResizing){
vBar.runtimeStyle.left = e.clientX + document.documentElement.scrollLeft;
document.selection.empty();
}else if(this._yResizing){
hBar.runtimeStyle.top = e.clientY + document.documentElement.scrollTop;
document.selection.empty();
}
return;
}
if(e.offsetX >= (e.target.offsetWidth - this._edgeThreshold)){
this._xResizeCursorVisible = true;
e.target.runtimeStyle.cursor = "e-resize";
}else if(e.offsetY >= (e.target.offsetHeight - this._edgeThreshold)){
this._yResizeCursorVisible = true;
e.target.runtimeStyle.cursor = "s-resize";
}else{
this._xResizeCursorVisible = false;
this._yResizeCursorVisible = false;
if(e.target.style.cursor){
e.target.runtimeStyle.cursor = e.target.style.cursor;
}else{
e.target.runtimeStyle.cursor = "";
}
}
}
function ComponentGeek$TableResizer$MouseUp(e){
// マウスアップイベント
// サイズ変更中の場合は変更を行う
if(this._target == null) return;
this._endX = e.clientX;
this._endY = e.clientY;
var tbl = $get(this._tableId);
if(!tbl) return;
if(this._xResizing){
// 幅変更中
if(this._startX == null) return;
// 新しい幅
var newWidth = this._target.offsetWidth + (this._endX - this._startX);
// 閾値以上の場合はサイズを適用,そうでない場合、最小幅設定
if(newWidth > this._sizeThreshold){
// ヘッダセル取得
var head = this.GetFirstColumn(tbl, this._target.cellIndex);
if(head) head.style.width = newWidth;
}else{
// ヘッダセル取得
var head = this.GetFirstColumn(tbl, this._target.cellIndex);
if(head) head.style.width = this._sizeThreshold;
}
}else if(this._yResizing){
// 縦幅変更中
if(this._startY == null) return;
// 新しい高さ
var newHeight = this._target.offsetHeight + (this._endY - this._startY);
var rowSpan = this._target.rowSpan;
for(var i = 0;i<rowSpan;++i){
var row = tbl.rows(this._target.parentElement.rowIndex + i);
for(var j=0;j<row.cells.length;++j){
if((newHeight/rowSpan) > this._sizeThreshold){
row.cells(j).style.height = newHeight/rowSpan;
}else{
row.cells(j).style.height = this._sizeThreshold;
}
}
}
}
tbl.releaseCapture();
this.Clear();
}
ComponentGeek.TableResizer.registerClass("ComponentGeek.TableResizer");
以下のようにテーブルのIDを引数にしてRegisterEventを呼び出して、リサイズできるようにします。
Sys.Application.add_load(function(){
Resizer = new ComponentGeek.TableResizer();
Resizer.RegisterEvent( 'testtable');
});
以下動作例。本当ならマウスをドラッグしているときに縦棒が表示されるはずなんですが、このページだとスタイルシートの関係で表示されないみたいです。
| 1 | 2 | 3 | 4 |
|---|---|---|---|
| 1,1 | 1,2 | 1,3 | 1,4 |
| 2,1 | 2,2 | 2,3 | 2,4 |
2013/1/8 追記 現在サイトは ASP.NET AJAX を使用していません。上記の表は本サイト上では動作しません。
馬鹿な質問で恐縮ですが、GridViewで使った場合、Pagingでヘッダの上にPaging用の行ができた場合(colspanでセル結合されている)、上手く動作させるには、どこを修正すればよいでしょうか。
よろしくお願いします。