svgを学習していて気が付いたんですが、canvasはflashのように表示内容からソースコードを追う事が難しいのですが、svgはタグが生成されるので、タグと属性をそのままコピーするだけで同じ表現が複製出来てしまうんですね。
ただ、アニメーションや、イベント効果など複雑な動作は、生成されるjavascriptを元にしなければいけないんですが、どちらにしても、webページと同じでソースコードは後追いが可能な技術なんですね。
もともとwebページでjavascriptを使うと言うことはどんだけ難読化しても隠しようがないので、それと同じであるのは変わりないのでさほど問題でもないんですが、難読化するぐらいなら、canvas使った方がいいという事なんでしょうね。
javascript簡易バージョン
前回書いたjavascript版のソースコードですが、もう少し簡単にする事ができたので、まずはそちらを載せておきますね。
;svgDraw = (function(){
/*
selector : "#svg"
w , h : svg-size
shapes : [ type , value & options ]
*/
var $$ = function(selector , option , shapes){
var target = (selector) ? document.querySelector(selector) : document.body;
if(!target){return;}
var svg = this.make.svg(option);
if(!svg){return;}
target.appendChild(svg);
for(var i=0; i<shapes.length; i++){
this.make.shapes(svg , shapes[i]);
}
};
$$.prototype.make = {
namespace : "http://www.w3.org/2000/svg",
xlink : "http://www.w3.org/1999/xlink",
css : function(parent , css){
// var tag = document.createElementNS(this.namespace , "link");
var tag = document.createElement("link");
tag.rel = "stylesheet";
tag.href = css;
parent.appendChild(tag);
},
svg : function(option){
if(!option){return;}
var svg = document.createElementNS(this.namespace , "svg");
for(var i in option){
if(i === "css"){
// this.css(document.getElementsByTagName("head")[0] , option[i]);
this.css(svg , option[i]);
}
else{
svg.setAttribute(i , option[i]);
}
}
return svg;
},
shapes : function(svg , option){
if(!option){return;}
var elm = document.createElementNS(this.namespace , option[0]);
svg.appendChild(elm);
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]);
}
if(typeof option[2] === "string"){
elm.textContent = option[2];
}
else if(typeof option[2] === "object" && option[2].length){
for(var i=0; i<option[2].length; i++){
this.shapes(elm , option[2][i]);
}
}
else{
}
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 "";
}
}
};
return $$;
})();
<!DOCTYPE html>
<html>
<head>
<title>svg</title>
<script src="svg.js"></script>
</head>
<body>
<h1>SVG</h1>
<div id="svg"></div>
<script>
new svgDraw("#svg" , {width:600 , height:200 , id : "test_1" , version : "1.1" , viewBox : "0 0 1200 400"} , [
["rect" , {x:0 , y:0 , width:160 , height:160 , fill:"skyblue" , stroke:"blue" , "stroke-width":"4"}],
["rect" , {x:0 , y:0 , width:80 , height:80 , fill:"tomato" , rx:8 , ry:8 , transform:{rotate:45 , translate:{x:80 , y:20}}}],
["circle" , {cx:0 , cy:0 , r:80 , fill : "rgba(255,0,0,0.5)" , transform:{translate : {x:250 , y:80}}}],
["ellipse" , {cx:0 , cy:0 , rx:80 , ry:40 , fill : "rgba(0,0,255,0.5)" , transform:{translate : {x:400 , y:80} , rotate : 0}}],
["line" , {x1:400,y1:0,x2:480,y2:100,"stroke-width":8 , stroke:"lightgreen"}],
["polyline" , {points:"50,375 150,375 150,325 250,325 250,375 350,375 350,250 450,250 450,375 550,375 550,175 650,175 650,375 750,375 750,100 850,100 850,375 950,375 950,25 1050,25 1050,375 1150,375" ,"stroke-width":8 , stroke:"blue" , fill:"none"}],
["polygon" , {points:"350,75 379,161 469,161 397,215 423,301 350,250 277,301 303,215 231,161 321,161" ,"stroke-width":4 , stroke:"brown" , fill:"yellow" ,transform:{rotate:5}}]
]);
</script>
</body>
</html>
表示も前回と同じである事がわかります。
ソースコードの行数が、前回は300行ぐらいあったのですが、今回は、88行という事で1/3以下に抑える事ができました。
ポイントは、シェイプのタグ別に作っていた関数を全て1つにまとめて記述してみました。
"shapes"という関数にまとめて書いているんですが、タグと属性をそのまま指定する仕様に変更しています。
そのためこれまで「stroke-width」はオブジェクトのネイティブkeyとして使えなかったので「strokeW」としていましたが、ダブルクォートを使って、「"stroke-width":2」という風に指定するようにしました。
これにより、想定していない属性も、指定する事が可能になりました。
また、transformは深い階層になるので、なるべく配列で指定できるようにしていますが、そのまま"rotate"や"translate","scale"などを指定しても使えるようにしています。
何にせよ、これでかなり効率化が進んだので、他のsvgオブジェクトの学習に集中する事ができそうです。
テキストの扱い
svgは、テキストも要素として作成する事ができます。
座標などがコントロールできるので、必要な説明書きなどが表示可能です。
htmlでの記述は以下のように書きます。
<svg width="600" height="200" id="test_1" version="1.1">
<text x="0" y="32" font-size="32" fill="red">Hello world !!!</text>
</svg>
上記ソースのjavascriptで記述する場合は、
<script>
new svgDraw("#svg" , {width:600 , height:200 , id : "test_1" , version : "1.1"} , [
["text" , {x:0,y:32,"font-size":"32",fill:"red"} , "Hello world !!!"]
]);
</script>
非常にシンプルなので説明などはいらないと思いますが、js記述は、指定引数の3番目に文字列を入れるようにしてあります。
ただし、テキストの一部だけに別装飾をさせたい場合や、テキストの改行を入れる事ができないため、そうした場合は、別オブジェクトとしてテキストを生成する必要があります。
この辺が柔軟になるともっと便利に使えるのに・・・
一つ注意点として、テキスト表示する時のデフォルト状態では、y軸を0にすると、テキストが表示されません。
※指定座標の上に表示されているため、svgエリア外に表示されてしまいます。
これを回避するために、指定している"font-size"と同じ値をyに指定する事で文字が表示されます。
この辺がhtml要素と少し違和感がありますね。
外部画像ファイルの扱い
svgは、それだけでベクターでの画像生成が行えるのですが、外部のピクト画像(svgも可)なども読み込んで同じsvg内部で表示する事ができます。
グラフを作った時に、任意の位置にロゴやアイコンを設置したい場合に便利ですね。
html記述
<svg width="600" height="200" id="test_1" version="1.1">
<text x="0" y="32" font-size="32" fill="red">Hello-world</text>
<image x="0" y="40" width="32px" height="32px" href="icon.png"></image>
</svg>
javascript記述
<script>
new svgDraw("#svg" , {width:600 , height:200 , id : "test_1" , version : "1.1"} , [
["text" , {x:0,y:32,"font-size":"32",fill:"red"} , "Hello-world"],
["image" , {x:0 , y:40 , width:"32px" , height:"32px", "href":"icon.png"}]
]);
</script>
先ほどのtextの下に表示してみました。
これも非常にシンプルなので、htmlタグが理解できていれば、難なく使えるでしょう。
サンプルで使用したpng形式以外でも、jpegもgifも使えるようです。
次回予告
svgアニメーションをしっかりと理解して、html装飾ができるようにがんばります!!!
0 件のコメント:
コメントを投稿