イベント一覧
svgはhtmlと同じdom構造のため、それぞれの要素に対して通常の要素イベントは、大体設置できるようです。 ちなみに、リファレンスページに書かれているのは以下の通りです。【通常要素イベント】 onfocusin = "<anything>" onfocusout = "<anything>" onactivate = "<anything>" onclick = "<anything>" onmousedown = "<anything>" onmouseup = "<anything>" onmouseover = "<anything>" onmousemove = "<anything>" onmouseout = "<anything>"そして、svgタグだけに記載できるのは、下記のイベント。
【svgタグ専用イベント】 onunload = "<anything>" onabort = "<anything>" onerror = "<anything>" onresize = "<anything>" onscroll = "<anything>" onzoom = "<anything>"また、アニメーション専用のイベントも用意されています。
【アニメーションタグ専用イベント】 onbegin = "<anything>" onend = "<anything>" onrepeat = "<anything>"アニメーションの開始や終了タイミングを取得できるようですね。
コードで学習
svgタグ内にscriptタグを記載して、その関数を呼び出すというオーソドックスタイプでコーディングしてみました。 個別に管理できる利点はありますが、無名関数にできないデメリットがありますが、idやclassを割り当てなくてもダイレクトにイベント設置できるのは利点ですね。クリックして拡大・縮小
<svg width="220" height="220" id="test_1" version="1.1">
<g transform="translate(4,4)" onclick="scaleEvent(this)">
<rect x="0" y="0" width="100" height="100" fill="skyblue" stroke="blue" stroke-width="4"></rect>
<rect x="0" y="0" width="60" height="60" fill="tomato" rx="8" ry="8" transform="translate(20 20)"></rect>
</g>
<script>
function scaleEvent(elm){
if(elm.getAttribute("data-flg")){
elm.setAttribute("transform" , "translate(4,4)");
elm.removeAttribute("data-flg");
}
else{
elm.setAttribute("transform" , "translate(4,4) scale(2)");
elm.setAttribute("data-flg" , "1");
}
}
</script>
</svg>
表示されているオブジェクトをクリックすると、拡大したり縮小したりするようにイベント処理してみました。
ちなみに、拡縮状態をトグル対応するために、data-flg属性を付与して対応してます。
サンプル
マースオーバーしてアニメーションする
<svg width="220" height="220" id="test_1" version="1.1">
<g transform="translate(4,4)" onmouseover="scaleEventOn(this)" onmouseout="scaleEventOff(this)">
<rect x="0" y="0" width="100" height="100" fill="skyblue" stroke="blue" stroke-width="4"></rect>
<rect x="0" y="0" width="60" height="60" fill="tomato" rx="8" ry="8" transform="translate(20 20)"></rect>
</g>
<script>
function scaleEventOn(elm){
elm.setAttribute("transform" , "translate(4,4) scale(2)");
}
function scaleEventOff(elm){
elm.setAttribute("transform" , "translate(4,4)");
}
</script>
</svg>
マウスがオブジェクトに重なった時に発生するイベントは非常に有意義です。
サンプル
コードで学習2
次はjsだけでsvgを構築し、イベント対応してみます。 svgの基本ライブラリは、過去記事のSVG学習 3日目「Javascriptで描画」からバージョンアップさせていますので、下記ライブラリを使ってください。svgライブラリ
;$$svg = (function(){
var $$ = function(selector , option , shapes){
var target = (selector) ? document.querySelector(selector) : document.body;
if(!target){return;}
var svg = target.querySelector("svg");
if(!svg){
svg = $$.prototype.make.svg(option);
}
target.appendChild(svg);
for(var i=0; i<shapes.length; i++){
$$.prototype.make.shapes(svg , shapes[i]);
}
};
$$.prototype.add = function(target , shapes){
if(!target){return;}
if(typeof target === "string"){
target = document.querySelector(selector);
}
if(!target){return;}
for(var i=0; i<shapes.length; i++){
$$.prototype.make.shapes(target , shapes[i]);
}
};
$$.prototype.make = {
namespace : "http://www.w3.org/2000/svg",
xlink : "http://www.w3.org/1999/xlink",
svg : function(option){
if(!option){return;}
var svg = document.createElementNS(this.namespace , "svg");
for(var i in option){
svg.setAttribute(i , option[i]);
}
return svg;
},
shapes : function(target , option){
if(!option){return;}
var elm = document.createElementNS(this.namespace , option[0]);
target.appendChild(elm);
// attribute
for(var i in option[1]){
if(i === "transform" && typeof option[1][i] === "object"){
option[1][i] = this.transform(option[1][i]);
}
elm.setAttribute(i , option[1][i]);
}
// string or childNodes
if(typeof option[2] === "string" || typeof option[2] === "number"){
// elm.textContent = option[2];
elm.innerHTML = option[2];
}
else if(option[2] && typeof option[2] === "object" && option[2].length){
for(var i=0; i<option[2].length; i++){
this.shapes(elm , option[2][i]);
}
}
// event
if(option[3] && typeof option[3] === "object" && option[3].length){
for(var i=0; i<option[3].length; i++){
$$event(elm , option[3][i][0] , option[3][i][1]);
}
}
return elm;
},
transform:function(option){
var transform = [];
if(option.translate){
var tx = (option.translate.x) ? option.translate.x : 0;
var ty = (option.translate.y) ? option.translate.y : 0;
transform.push("translate("+ tx +" "+ ty +")");
}
if(option.rotate){
transform.push("rotate("+ option.rotate +")");
}
if(option.scale){
transform.push("scale("+ option.scale +")");
}
if(transform.length){
return transform.join(" ");
}
else{
return "";
}
}
};
var $$event = function(target, mode, func){
if (typeof target.addEventListener !== "undefined"){
target.addEventListener(mode, func, false);
}
else if(typeof target.attachEvent !== "undefined"){
target.attachEvent('on' + mode, function(){func.call(target , window.event)});
}
};
return $$;
})();
オブジェクトをマウスでドラッグして移動させる
<div id="svg"></div>
<script>
new $$svg("#svg" , {width:300 , height:300 , version : "1.1" , style : "border:1px solid black;"} , [
["g" , {id : "drag" , transform:{translate:{x:10,y:10}}} , [
["rect" , {x:0 , y:0 , width:100 , height:100 , fill:"skyblue" , stroke:"blue" , "stroke-width":"4"}],
["rect" , {x:0 , y:0 , width:60 , height:60 , fill:"tomato" , rx:8 , ry:8 , transform:{translate:{x:20 , y:20}}}],
]]
]);
var elm = document.getElementById("drag");
elm.onmousedown = function(e){
var target = this;
target.setAttribute("data-drag-flg" , "1");
target.setAttribute("data-pageX" , e.pageX);
target.setAttribute("data-pageY" , e.pageY);
target.setAttribute("data-posX" , target.transform.baseVal[0].matrix.e);
target.setAttribute("data-posY" , target.transform.baseVal[0].matrix.f);
//console.log(target.transform.baseVal[0].matrix.e +"/"+ target.transform.baseVal[0].matrix.f);
};
window.onmouseup = function(e){
var target = document.getElementById("drag");
if(!target.getAttribute("data-drag-flg")){return;}
target.removeAttribute("data-drag-flg");
};
elm.onmousemove = function(e){
var target = this;
if(!target.getAttribute("data-drag-flg")){return;}
var pageX = Number(target.getAttribute("data-pageX"));
var pageY = Number(target.getAttribute("data-pageY"));
var posX = Number(target.getAttribute("data-posX"));
var posY = Number(target.getAttribute("data-posY"));
var diffX = pageX - e.pageX;
var diffY = pageY - e.pageY;
target.transform.baseVal[0].matrix.e = posX - diffX;
target.transform.baseVal[0].matrix.f = posY - diffY;
};
</script>
ライブラリも長くなっているので、codepenに書いてembedしました。
サンプル
See the Pen svg - drag by YugetaKoji (@geta1972) on CodePen.
svgのtransform情報の取得とmatrix属性について
svgのそれぞれのシェイプのx,y座標やwidth,heightサイズなどを取得するのは、getAttributeで簡単に取得できますが、transform情報を取得するのは、少し手間がかかります。 文字列としてscale,translate,rotateなどを取得して、正規表現などで分解してもいいのですが、svgの座標記述などは複数の記述方法があり、なかなかめんどくさい作業になります。 そんな時に、matrixプロパティを取得して行う方法があるので、これを覚えておくと便利に値の取得ができます。matrixのアクセス方法
エレメントのtransform属性の下にある"baseVal"の最初の配列にアクセスし、その直下にmatrixが存在します。対象Element.transform.baseVal[0].matrix
> SVGMatrix
a:1
b:0
c:0
d:1
e:20
f:20
ここで取得できる情報がa~fまである事がわかります。
それぞれの情報は以下の通りです。
ちなみに、transformが設定されていない場合は、baseVal配列にはデータが無いため、それ以下は"undefined"になるので、事前に判定処理が必要です。
a:scale-x
b:rotate-p
c:rotate-m
d:scale-y
e:transform-x
f:transform-y
それぞれの値が細かく入っています。
座標を取得したい場合は、以下のような記述ですね。
対象Element.transform.baseVal[0].matrix.e; // X座標
対象Element.transform.baseVal[0].matrix.f; // Y座標
0 件のコメント:
コメントを投稿