<canvas width=480 height=30 id="slider1"
style='background-color:red'></canvas><br>
<canvas width=230 height=45 id="slider2"
style='background-color:blue'></canvas>
<canvas width=230 height=45 id="slider3"
style='background-color:lightgreen'></canvas><br>
<canvas width=350 height=30 id="slider4"></canvas>
<input type=text style="width:5em" id="text1">
<script type="text/javascript">
function $E(name){ return document.getElementById(name); }
// デフォルトスライダー 0-100、10刻みスケール
sld1 = new hiSlider($E("slider1"),null);
// 初期値指定 30 精度少数以下1桁 20刻みスケール
sld2 = new hiSlider($E("slider2"),{val:30,precision:1
,disp_scale:20,text_color:'white'});
// スケールに値表示
var opt3={min_val:-200,max_val:800,disp_scale:200,val:400,
scale_vals:[200,0,400,600]};
sld3 = new hiSlider($E("slider3"),opt3);
// 現在値非表示 イベントコールバック
var opt4={min_val:380,max_val:730,disp_scale:50,val:530,
scale_vals:[380,480,580,680],disp_val:false,
callback:dispVal};
sld4 = new hiSlider($E("slider4"),opt4);
function dispVal(slider,t,e){ // コールバック関数
$E("text1").value=slider.val;
}
HTMLスライダーをcanvasで作る;取り急ぎ
WEB画面でスライダーが欲しくなることは頻繁にあります。
これまではFlashで簡単に作成できましたが、Flashの動かない貧弱な
ブラウザが増えてきたため対処が必要です。
<range>はまだ殆どのブラウザで動作しません。jQueryによる実装も
滑らかには動作しません。なかなか良いものが見つからないので、
canvasで単純なものを実装することにしました。
使い方は
- HTML記述でcanvasを定義する
- JavaScriptでhiSliderをcanvasを引数でnewする
です。冒頭のスライダーをどう定義しているか[上のスライダー定義を表示する]
ボタンで見ることができます。
hiSliderの構築子にはオプション指定があり、次の設定ができます。
設定項目 | 型 | デフォルト | 説明 |
val | 数値 | 50 | 初期値 |
min_val | 数値 | 0 | 最小値 |
max_val | 数値 | 100 | 最大値 |
disp_val | boolean | true | 現在値を表示する/しない |
disp_scale | 0 | true | 刻みの単位 |
scale_vals | 数値配列 | null | 目安の数値の並び |
precision | 数値 | 0 | 少数点以下何桁までだすか |
text_colr | 色を表す文字列 | 'black' | 数値と刻みの色 |
callback | 関数 | null |
値に変化があった時呼び出す関数 |
callback関数は3つの引数を持ちます。
- イベントの起こったhiSlider
- マウスのイベント種を示す文字; "d"=down,"m"=move,"u"=up,"o"=out
- マウスイベント生情報
冒頭のサンプルでは一番下の白/黒スライダがcallback関数を使っており
callback関数でスライダの値をHTMLの<input type=text>領域にセットしています。
IE9,GoogleChrome,Safari(win),firefoxでは問題なく動きました。
残念ながらiPadのSafariではハンドルをドラッグすることは
できず、クリックで位置を変えることができるだけです。
コード
ちょっと長いですがコードを載せます。hiSlider.jsとsliderSample.htmlに
分かれています。
sliderSample.htmlで呼んでいるexcanvas.jsはIE8以前のIEでcanvasを動かす
ためのもので、IE9そのたcanvasが動作するブラウザでは不要です。
IE8以前のブラウザで見る場合適当なところにダウンロードして、その
urlに書き換えてください。
hiSlider.startX = 15;
hiSlider.endX = 20;
hiSlider.startY = 3;
hiSlider.startY_v = 15;
hiSlider.barHeight = 5;
function hiSlider(canvas_,option_){
this.canvas = canvas_;
this.context = this.canvas.getContext('2d');
this.rect = this.canvas.getBoundingClientRect();
var _this=this;
this.canvas.onmousedown=function(e){_this.mouseDown(e);}
this.canvas.onmouseup =function(e){_this.mouseUp(e);}
this.canvas.onmouseout =function(e){_this.mouseOut(e);}
this.canvas.onmousemove=function(e){_this.mouseMove(e);}
this.dragging = false;
if( option_ ){
this.callback = option_.callback;
this.min_val = option_.min_val===undefined?0:option_.min_val;
this.max_val = option_.max_val===undefined?100:option_.max_val;
this.val = option_.val===undefined?50:option_.val;
this.disp_val = option_.disp_val===undefined?true:option_.disp_val;
this.disp_scale = option_.disp_scale===undefined?10:option_.disp_scale;
this.scale_vals = option_.scale_vals;
this.precision = option_.precision===undefined?0:option_.precision;
this.text_color = option_.text_color===undefined?"black":option_.text_color;
}
else{
this.callback = null;
this.min_val = 0;
this.max_val = 100;
this.val = 50;
this.disp_val = true;
this.disp_scale = 10;
this.scale_vals = null;
this.precision = 0;
this.text_color = "black";
}
this.x1 = hiSlider.startX;
if( !this.disp_val &&!this.scale_vals ){
this.y1 = hiSlider.startY; // 必要サイズ22
}
else{
this.y1 = hiSlider.startY_v;// 最低必要サイズ30
}
this.x2 = this.canvas.width-hiSlider.endX;
this.y2 = this.y1 +hiSlider.barHeight;
this.w = this.canvas.width-(hiSlider.startX+hiSlider.endX);
this.h = hiSlider.barHeight;
this.r = this.w/(this.max_val-this.min_val);
this.setValue(this.val);
this.draw();
if( this.callback ) this.callback(this,'s',null);
}
hiSlider.prototype.draw = function(){
var canvas = this.canvas;
var context= this.context;
context.save(); // おまじない
// バー表示
// 面
context.clearRect(0,0,canvas.width,canvas.height);
context.beginPath();
context.rect(this.x1,this.y1,this.w,this.h);
context.fillStyle = 'rgba(200,200,200,0.5)';
context.fill();
// 下(明)
context.lineWidth =1;
context.beginPath();
context.moveTo(this.x1,this.y2);
context.lineTo(this.x2,this.y2);
context.lineTo(this.x2,this.y1);
context.strokeStyle = 'rgba(255,255,255,0.8)';
context.stroke();
// 上(暗)
context.beginPath();
context.moveTo(this.x1,this.y2);
context.lineTo(this.x1,this.y1);
context.lineTo(this.x2,this.y1);
context.strokeStyle = 'rgba(0,0,0,0.8)';
context.stroke();
// ハンドル表示(5角形)
this.val_x = this.r*(this.val-this.min_val)+this.x1;
context.beginPath();
context.moveTo(this.val_x,this.y1);
context.lineTo(this.val_x+5,this.y1+7);
context.lineTo(this.val_x+5,this.y1+15);
context.lineTo(this.val_x-5,this.y1+15);
context.lineTo(this.val_x-5,this.y1+7);
context.closePath();
context.fill();
context.stroke();
// スケール表示
context.fillStyle = this.text_color;
context.strokeStyle = this.text_color;
if( this.disp_scale>0 ){
for(var i=this.min_val;i<=this.max_val;i+=this.disp_scale){
context.beginPath();
var x= this.r*(i-this.min_val)+this.x1;
context.moveTo(x,this.y1-2);
context.lineTo(x,this.y1-4);
context.stroke();
}
}
// スケール文字列表示
if( this.scale_vals ){
for(var i=0;i<=this.scale_vals.length;++i){
var v=this.scale_vals[i];
if( v>=this.min_val && v<=this.max_val ){
context.font = "12px arial"; // フォント
var text = String(v);
var x=this.r*(v-this.min_val)+this.x1;
var offset= text.length*3.0;
context.fillText(text
,x-offset
,this.y1-5);
}
}
}
// 値表示
if( this.disp_val ){
context.font = "12px arial"; // フォント
var text = String(this.val);
var offset= text.length*3.0;
var voffset= -5;
if( this.scale_vals ) voffset=26;
context.fillText(text
,this.val_x-offset
,this.y1+voffset);
}
//
context.restore(); // おまじない
}
hiSlider.prototype.setValue = function(v){
if( this.precision == 0){
this.val = Math.round(v);
}
else{
this.val = v.toFixed(this.precision);
}
}
hiSlider.prototype.setEventValue = function(e){
var pos = e.clientX-this.rect.left-this.x1;
this.setValue(this.min_val + pos/this.r);
if( this.val < this.min_val) this.val=this.min_val;
else if( this.val > this.max_val) this.val=this.max_val;
this.draw();
}
hiSlider.prototype.mouseDown = function(e){
this.dragging=true;
this.setEventValue(e)
if( this.callback ) this.callback(this,'d',e);
}
hiSlider.prototype.mouseMove = function(e){
if( this.dragging ){
this.setEventValue(e);
if( this.callback ) this.callback(this,'m',e);
}
}
hiSlider.prototype.mouseUp = function(e){
this.dragging=false;
if( this.callback ) this.callback(this,'u',e);
}
hiSlider.prototype.mouseOut = function(e){
if( this.callback&& this.dragging) this.callback(this,'o',e);
this.dragging=false;
}
<!-- saved from url=(0014)about:internet -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<html>
<head>
<!--[if lt IE 9]>
<script type="text/javascript" src="../../../js/excanvas.js"></script>
<![endif]-->
<script type="text/javascript" src="./hiSlider.js" charset="UTF-8"></script>
</head>
<body>
<!-- ===== CANVASを配置 ===== -->
<canvas width=480 height=30 id="slider1"
style='background-color:red'></canvas><br>
<canvas width=230 height=45 id="slider2"
style='background-color:blue'></canvas>
<canvas width=230 height=45 id="slider3"
style='background-color:lightgreen'></canvas><br>
<canvas width=350 height=30 id="slider4"></canvas>
<input type=text style="width:5em" id="text1">
<!-- ===== CANVASをhiSliderに登録 ===== -->
<script type="text/javascript">
function $E(name){ return document.getElementById(name); }
// デフォルトスライダー 0-100、10刻みスケール、
sld1 = new hiSlider($E("slider1"),null);
// 初期値指定 30 精度少数以下1桁 20刻みスケール
sld2 = new hiSlider($E("slider2"),{val:30,precision:1
,disp_scale:20,text_color:'white'});
// スケールに値表示
var opt3={min_val:-200,max_val:800,disp_scale:200,val:400,
scale_vals:[200,0,400,600]};
sld3 = new hiSlider($E("slider3"),opt3);
// 現在値非常時 イベントコールバック
var opt4={min_val:380,max_val:730,disp_scale:50,val:530,
scale_vals:[380,480,580,680],disp_val:false,
callback:dispVal};
sld4 = new hiSlider($E("slider4"),opt4);
// コールバック関数
function dispVal(slider,t,e){
$E("text1").value=slider.val; // slider値をtextにセット
}
</script>
</body>
ダウンロード
ダウンロードファイルを用意しました。右クリック->[対象をファイルに保存]でダウンロードできます。
機能をどこまで付けるか
当初はオプション無しの単純なものをと考えていたのですが、最大値、最小値、目盛、
コールバックなどは最低でも必要だとして、追加し、少し肥大化しました。
多分さらにオプションは増えるでしょう。
取り急ぎの記事なので
説明が足りないとは思います。その内コードの説明なども入れます。
コメント