1 // svgcanvas.js
  2 // SVG 動的生成サポートライブラリ
  3 //
  4 // 簡単な使い方:
  5 //
  6 // (1) SVGCanvas オブジェクトを生成
  7 //   var canvas = new SVGCanvas(width, height);
  8 // (2) SVGLayer オブジェクトを生成
  9 //   var layer = new SVGLayer(id);
 10 // (3) レイヤに描画
 11 //   layer.fillColor = "black";
 12 //   layer.text("Hello, world!", 0, 0); // <canvas> プギャー
 13 // (4) キャンバスにレイヤを追加
 14 //   canvas.addLayer(layer);
 15 // (5) 要素にキャンバスを追加
 16 //   canvas.appendTo(document.body);
 17 //
 18 // * <canvas>なんてウンコは使ってられないぜ
 19 // * SVGAnchor を使えばリンクも設定できるぜ
 20 // * 細かい属性は思いっきり端折ってやったぜ
 21 // 
 22 
 23 
 24 /**
 25  * @fileOverview SVG の動的生成を補助するライブラリです。
 26  */
 27  
 28  /**
 29  * svg 要素を管理します。
 30  * @class
 31  * @param {Number} width  幅
 32  * @param {Number} height 高さ
 33  */
 34 function SVGCanvas() {
 35     this.initialise.apply(this, arguments);
 36 }
 37 SVGCanvas.prototype = {
 38 	SVG_NS: 'http://www.w3.org/2000/svg',
 39 	XLink_NS: 'http://www.w3.org/1999/xlink',
 40 	/** svg 要素
 41 	 * @type element
 42 	 */
 43 	svg: null,
 44 	/** 幅
 45 	 * @type Number
 46 	 */
 47 	width: null,
 48 	/** 高さ
 49 	 * @type Number
 50 	 */
 51 	height: null,
 52 	/** コンストラクタから自動的に呼ばれ、初期化処理を行います。 */
 53 	initialise: function(width, height) {
 54 		this.svg = document.createElementNS(this.SVG_NS, "svg");
 55 		//this.svg.setAttributeNS(null, "xmlns:xlink",  this.XLink_NS);
 56 		this.svg.setAttributeNS(null, "width",  width);
 57 		this.svg.setAttributeNS(null, "height", height);
 58 		this.width  = width;
 59 		this.height = height;
 60 	},
 61 	/** 指定された要素に子要素として追加します。
 62 	 * @param {element} x 親要素
 63 	 */
 64 	appendTo: function(x) {
 65 		x.appendChild(this.svg);
 66 	},
 67 	/** 指定された要素から削除します。
 68 	 * @param {element} x 親要素
 69 	 */
 70 	removeFrom: function(x) {
 71 		x.removeChild(this.svg);
 72 	},
 73 	/** 子要素を追加します。
 74 	 * @param {Object} x 親要素
 75 	 */
 76 	add: function(x) {
 77 		this.svg.appendChild(x.element);
 78 	},
 79 	/** 子要素を削除します。
 80 	 * @param {Object} x 親要素
 81 	 */
 82 	remove: function(x) {
 83 		this.svg.removeChild(x.element);
 84 	}
 85 };
 86 
 87  /**
 88  * SVG の各種子要素を管理します。
 89  * @class
 90  * @param {Number} width  幅
 91  * @param {Number} height 高さ
 92  * @property {String} id ID
 93  * @property {String} strokeColor   ストロークの色
 94  * @property {Number} strokeWidth   ストロークの幅
 95  * @property {Number} strokeOpacity ストロークの透明度
 96  * @property {String} fillColor   塗りつぶしの色
 97  * @property {Number} fillOpacity 塗りつぶしの透明度
 98  */
 99 function SVGElement() {
100     this.initialise.apply(this, arguments);
101 }
102 SVGElement.prototype = {
103 	SVG_NS: 'http://www.w3.org/2000/svg',
104 	XLink_NS: 'http://www.w3.org/1999/xlink',
105 	/** 要素
106 	 * @type element
107 	 */
108 	element: null,
109 	/** 要素名
110 	 * @type String
111 	 */
112 	name: null,
113 	_id: null,
114 	_strokeWidth: null,
115 	_strokeColor: null,
116 	_strokeOpacity: null,
117 	_fillColor: null,
118 	_fillOpacity: null,
119 	get id()  { return this._id; },
120 	set id(x) { this.element.setAttributeNS(null, "id", x); this._id = x; },
121 	get strokeColor()    { return this._strokeColor },
122 	set strokeColor(x)   { this.element.setAttributeNS(null, "stroke", x); this._strokeColor = x; },
123 	get strokeWidth()    { return this._strokeWidth },
124 	set strokeWidth(x)   { this.element.setAttributeNS(null, "stroke-width", x); this._strokeWidth = x; },
125 	get strokeOpacity()  { return this._strokeOpacity },
126 	set strokeOpacity(x) { this.element.setAttributeNS(null, "stroke-opacity", x); this._strokeOpacity = x; },
127 	get fillColor()      { return this._fillColor },
128 	set fillColor(x)     { this.element.setAttributeNS(null, "fill", x); this._fillColor = x; },
129 	get fillOpacity()    { return this._fillOpacity },
130 	set fillOpacity(x)   { this.element.setAttributeNS(null, "fill-opacity", x); this._fillOpacity = x; },
131 	/*
132 	_onClick:     null,
133 	_onMouseDown: null,
134 	_onMouseUp:   null,
135 	_onMouseMove: null,
136 	_onMouseOut:  null,
137 	_onMouseOver: null,
138 	_onActivate:  null,
139 	get onClick()      { return this._onClick },
140 	set onClick(x)     { this.element.setAttributeNS(null, "onclick", x); this._onClick = x; },
141 	get onMouseDown()  { return this._onMouseDown },
142 	set onMouseDown(x) { this.element.setAttributeNS(null, "onmousedown", x); this._onMouseDown = x; },
143 	get onMouseUp()    { return this._onMouseUp },
144 	set onMouseUp(x)   { this.element.setAttributeNS(null, "onmouseup", x); this._onMouseUp = x; },
145 	get onMouseMove()  { return this._onMouseMove },
146 	set onMouseMove(x) { this.element.setAttributeNS(null, "onmousemove", x); this._onMouseMove = x; },
147 	get onMouseOut()   { return this._onMouseOut },
148 	set onMouseOut(x)  { this.element.setAttributeNS(null, "onmouseout", x); this._onMouseOut = x; },
149 	get onMouseOver()  { return this._onMouseOver },
150 	set onMouseOver(x) { this.element.setAttributeNS(null, "onmouseover", x); this._onMouseOver = x; },
151 	get onActivate()   { return this._onActivate },
152 	set onActivate(x)  { this.element.setAttributeNS(null, "onactivate", x); this._onActivate = x; },
153 	*/
154 	/** コンストラクタから自動的に呼ばれ、初期化処理を行います。 */
155 	initialise: function(name, layer, stroke, fill) {
156 		this.name = name;
157 		this.element = document.createElementNS(this.SVG_NS, name);
158 		if (stroke) {
159 			this.strokeColor   = layer.strokeColor   ? layer.strokeColor   : "none"
160 			this.strokeWidth   = layer.strokeWidth   ? layer.strokeWidth   : "1"
161 			this.strokeOpacity = layer.strokeOpacity ? layer.strokeOpacity : "1"
162 		}
163 		if (fill) {
164 			this.fillColor     = layer.fillColor     ? layer.fillColor     : "none"
165 			this.fillOpacity   = layer.fillOpacity   ? layer.fillOpacity   : "1"
166 		}
167 	},
168 	/** 属性の値を取得します。
169 	 * @param  {String} name 属性名
170 	 * @return {undefined} 値
171 	 */
172 	getAttribute: function(name) {
173 		this.element.getAttributeNS(null, name);
174 	},
175 	/** 属性に値を設定します。
176 	 * @param {String}    name  属性名
177 	 * @param {undefined} value 値
178 	 */
179 	setAttribute: function(name, value) {
180 		this.element.setAttributeNS(null, name, value);
181 	}
182 };
183 
184 /**
185  * SVG のa 要素を管理します。
186  * @class
187  * @param {String} href URI
188  * @param {String} id   ID
189  */
190 function SVGAnchor() {
191     this.initialise.apply(this, arguments);
192 }
193 SVGAnchor.prototype = {
194 	SVG_NS: 'http://www.w3.org/2000/svg',
195 	XLink_NS: 'http://www.w3.org/1999/xlink',
196 	/** 要素
197 	 * @type element
198 	 */
199 	element: null,
200 	/** ID
201 	 * @type String
202 	 */
203 	id: null,
204 	/** コンストラクタから自動的に呼ばれ、初期化処理を行います。 */
205 	initialise: function(href, id) {
206 		this.element = document.createElementNS(this.SVG_NS, "a");
207 		this.element.setAttributeNS(this.XLink_NS, "xlink:href",  href);
208 		this.element.setAttributeNS(null, "id", id);
209 		this.id = id;
210 	},
211 	/** 要素を追加します。
212 	 * @param {Object} x 要素
213 	 */
214 	add: function(x) {
215 		this.element.appendChild(x.element);
216 	},
217 	/** 要素を削除します。
218 	 * @param {Object} x 要素
219 	 */
220 	remove: function(x) {
221 		this.element.removeChild(x.element);
222 	}
223 };
224 
225 /**
226  * SVG の g 要素を管理します。
227  * @class
228  * @param {String} id ID
229  */
230 function SVGLayer() {
231     this.initialise.apply(this, arguments);
232 }
233 SVGLayer.prototype = {
234 	SVG_NS: 'http://www.w3.org/2000/svg',
235 	XLink_NS: 'http://www.w3.org/1999/xlink',
236 	/** 要素
237 	 * @type element
238 	 */
239 	element: null,
240 	/** ID
241 	 * @type String
242 	 */
243 	id: null,
244     /* ストロークの幅
245      * @type Number
246      */
247 	strokeWidth: null,
248     /* ストロークの色
249      * @type String
250      */
251 	strokeColor: null,
252     /* ストロークの透明度
253      * @type Number
254      */
255 	strokeOpacity: null,
256     /* 塗りつぶしの色
257      * @type String
258      */
259 	fillColor: null,
260     /* 塗りつぶしの透明度
261      * @type Number
262      */
263 	fillOpacity: null,
264 	/** コンストラクタから自動的に呼ばれ、初期化処理を行います。 */
265 	initialise: function(id) {
266 		this.element = document.createElementNS(this.SVG_NS, "g");
267 		this.element.setAttributeNS(null, "id",  id);
268 		this.id = id;
269 		return this.element;
270 	},
271 	/** 配列からカンマ区切りの座標リストへ変換します。
272 	 * @param  {Array} x 配列
273      * @return {String} 文字列
274 	 */
275 	arrayToPoints: function(x) {
276 		var p = [];
277 		for (var i = 0; i < x.length; i++)
278 			p[i] = x[i].join(" ");
279 		return p.join(",");
280 	},
281 	/** 要素を追加します。
282 	 * @param {Object} x 要素
283 	 */
284 	add: function(x) {
285 		this.element.appendChild(x.element);
286 	},
287 	/** 要素を削除します。
288 	 * @param {Object} x 要素
289 	 */
290 	remove: function(x) {
291 		this.element.removeChild(x.element);
292 	},
293 	/*
294 	createSVGElement: function(name, stroke, fill) {
295 		var element = document.createElementNS(this.SVG_NS, name);
296 		if (stroke) {
297 			element.setAttributeNS(null, "stroke", this.strokeColor ? this.strokeColor : "none");
298 			element.setAttributeNS(null, "stroke-width", this.strokeWidth ? this.strokeWidth : "1");
299 			element.setAttributeNS(null, "stroke-opacity", this.strokeOpacity ? this.strokeOpacity : "1");
300 		}
301 		if (fill) {
302 			element.setAttributeNS(null, "fill", this.fillColor   ? this.fillColor   : "none");
303 			element.setAttributeNS(null, "fill-opacity", this.fillOpacity ? this.fillOpacity : "1");
304 		}
305 		return element;
306 	},
307 	*/
308 	/** 四角形を作成します。
309 	 * @param  {Number} x X 座標
310 	 * @param  {Number} y Y 座標
311 	 * @param  {Number} width  幅
312 	 * @param  {Number} height 高さ
313      * @return {SVGElement} SVGElement オブジェクト
314 	 */
315 	rect: function(x, y, width, height) {
316 		//var rect = this.createSVGElement("rect", true, true);
317 		var rect = new SVGElement("rect", this, true, true);
318 		rect.element.setAttributeNS(null, "x",      x);
319 		rect.element.setAttributeNS(null, "y",      y);
320 		rect.element.setAttributeNS(null, "width",  width);
321 		rect.element.setAttributeNS(null, "height", height);
322 		this.element.appendChild(rect.element);
323 		return rect;
324 	},
325 	/** 円を作成します。
326 	 * @param  {Number} cx 中心の X 座標
327 	 * @param  {Number} cy 中心の Y 座標
328 	 * @param  {Number} r  半径
329      * @return {SVGElement} SVGElement オブジェクト
330 	 */
331 	circle: function(cx, cy, r) {
332 		var circle = new SVGElement("circle", this, true, true);
333 		circle.element.setAttributeNS(null, "cx", cx);
334 		circle.element.setAttributeNS(null, "cy", cy);
335 		circle.element.setAttributeNS(null, "r",  r);
336 		this.element.appendChild(circle.element);
337 		return circle;
338 	},
339 	/** 楕円を作成します。
340 	 * @param  {Number} cx 中心の X 座標
341 	 * @param  {Number} cy 中心の Y 座標
342 	 * @param  {Number} rx X 軸方向の半径
343 	 * @param  {Number} ry Y 軸方向の半径
344      * @return {SVGElement} SVGElement オブジェクト
345 	 */
346 	ellipse: function(cx, cy, rx, ry) {
347 		var ellipse = new SVGElement("ellipse", this, true, true);
348 		ellipse.element.setAttributeNS(null, "cx", cx);
349 		ellipse.element.setAttributeNS(null, "cy", cy);
350 		ellipse.element.setAttributeNS(null, "rx", rx);
351 		ellipse.element.setAttributeNS(null, "ry", ry);
352 		this.element.appendChild(ellipse.element);
353 		return ellipse;
354 	},
355 	/** 直線を作成します。
356 	 * @param  {Number} x1 始点の X 座標
357 	 * @param  {Number} y1 始点の Y 座標
358 	 * @param  {Number} x2 始点の X 座標
359 	 * @param  {Number} y2 終点の Y 座標
360      * @return {SVGElement} SVGElement オブジェクト
361 	 */
362 	line: function(x1, y1, x2, y2) {
363 		var line = new SVGElement("line", this, true, false);
364 		line.element.setAttributeNS(null, "x1", x1);
365 		line.element.setAttributeNS(null, "y1", y1);
366 		line.element.setAttributeNS(null, "x2", x2);
367 		line.element.setAttributeNS(null, "y2", y2);
368 		this.element.appendChild(line.element);
369 		return line;
370 	},
371 	/** 折れ線を作成します。
372 	 * @param  {Array/String} points 座標のリスト
373      * @return {SVGElement} SVGElement オブジェクト
374 	 */
375 	polyline: function(points) {
376 		//var polyline = new SVGElement("polyline", this, true, false);
377 		var polyline = new SVGElement("polyline", this, true, true);
378 		polyline.element.setAttributeNS(null, "points", (points instanceof Array) ? this.arrayToPoints(points) : points);
379 		this.element.appendChild(polyline.element);
380 		return polyline;
381 	},
382 	/** 多角形を作成します。
383 	 * @param  {Array/String} points 座標のリスト
384      * @return {SVGElement} SVGElement オブジェクト
385 	 */
386 	polygon: function(points) {
387 		var polygon = new SVGElement("polygon", this, true, true);
388 		polygon.element.setAttributeNS(null, "points", (points instanceof Array) ? this.arrayToPoints(points) : points);
389 		this.element.appendChild(polygon.element);
390 		return polygon;
391 	},
392 	/** 文字列を作成します。
393 	 * @param  {String} str 文字列
394 	 * @param  {Number} x X 座標
395 	 * @param  {Number} y Y 座標
396      * @return {SVGElement} SVGElement オブジェクト
397 	 */
398 	text: function(str, x, y) {
399 		var text = new SVGElement("text", this, true, true);
400 		text.element.setAttributeNS(null, "x", x);
401 		text.element.setAttributeNS(null, "y", y);
402 		text.element.appendChild(document.createTextNode(str));
403 		this.element.appendChild(text.element);
404 		return text;
405 	},
406 	/** 画像を作成します。
407 	 * @param  {String} src URI
408 	 * @param  {Number} x X 座標
409 	 * @param  {Number} y Y 座標
410 	 * @param  {Number} width  幅
411 	 * @param  {Number} height 高さ
412      * @return {SVGElement} SVGElement オブジェクト
413 	 */
414 	image: function(src, x, y, width, height) {
415 		var image = new SVGElement("image", this, false, false);
416 		image.element.setAttributeNS(this.XLink_NS, "xlink:href", src);
417 		if (x) image.element.setAttributeNS(null, "x", x);
418 		if (y) image.element.setAttributeNS(null, "y", y);
419 		if (width)  image.element.setAttributeNS(null, "width",  width);
420 		if (height) image.element.setAttributeNS(null, "height", height);
421 		this.element.appendChild(image.element);
422 		return image;
423 	},
424 };
425 
426 /**
427  * SVG の defs 要素を管理します。
428  * @class
429  */
430 function SVGDefinitions() {
431     this.initialise.apply(this, arguments);
432 }
433 SVGDefinitions.prototype = {
434 	SVG_NS: 'http://www.w3.org/2000/svg',
435 	XLink_NS: 'http://www.w3.org/1999/xlink',
436 	/** 要素
437 	 * @type element
438 	 */
439 	element: null,
440 	/** コンストラクタから自動的に呼ばれ、初期化処理を行います。 */
441 	initialise: function() {
442 		this.element = document.createElementNS(this.SVG_NS, "defs");
443 		return this.element;
444 	},
445 	/** 要素を追加します。
446 	 * @param {Object} x 要素
447 	 */
448 	add: function(x) {
449 		this.element.appendChild(x.element);
450 	},
451 	/** 要素を削除します。
452 	 * @param {Object} x 要素
453 	 */
454 	remove: function(x) {
455 		this.element.removeChild(x.element);
456 	}
457 };
458 
459 /**
460  * SVG の filter 要素を管理します。
461  * @param {String} id     ID
462  * @param {Number} x      X 座標
463  * @param {Number} y      Y 座標
464  * @param {Number} width  幅
465  * @param {Number} height 高さ
466  * @class
467  */
468 function SVGFilter() {
469     this.initialise.apply(this, arguments);
470 }
471 SVGFilter.prototype = {
472 	SVG_NS: 'http://www.w3.org/2000/svg',
473 	XLink_NS: 'http://www.w3.org/1999/xlink',
474 	/** 要素
475 	 * @type element
476 	 */
477 	element: null,
478 	/** ID
479 	 * @type String
480 	 */
481 	id: null,
482 	/** X 座標
483 	 * @type Number
484 	 */
485 	x: 0,
486 	/** Y 座標
487 	 * @type Number
488 	 */
489 	y: 0,
490 	/** 幅
491 	 * @type Number
492 	 */
493 	width:  0,
494 	/** 高さ
495 	 * @type Number
496 	 */
497 	height: 0,
498 	effects: [],
499 	/** コンストラクタから自動的に呼ばれ、初期化処理を行います。 */
500 	initialise: function(id, x, y, width, height) {
501 		this.element = document.createElementNS(this.SVG_NS, "filter");
502 		this.element.setAttributeNS(null, "id",  id);
503 		this.id = id;
504 		if (x) this.element.setAttributeNS(null, "x",  x);
505 		if (y) this.element.setAttributeNS(null, "y",  y);
506 		if (width)  this.element.setAttributeNS(null, "width",   width);
507 		if (height) this.element.setAttributeNS(null, "height",  height);
508 		return this.element;
509 	},
510 	/** 要素を追加します。
511 	 * @param {Object} x 要素
512 	 */
513 	add: function(x) {
514 		this.element.appendChild(x.element);
515 	},
516 	/** 要素を削除します。
517 	 * @param {Object} x 要素
518 	 */
519 	remove: function(x) {
520 		this.element.removeChild(x.element);
521 	}
522 };
523 
524 /**
525  * SVG の 原始フィルタを提供します。
526  * @static
527  */
528 var SVGFilterPrimitives = {
529 	SVG_NS: 'http://www.w3.org/2000/svg',
530 	XLink_NS: 'http://www.w3.org/1999/xlink',
531 	/** 原始フィルタを作成します。
532 	 * @param {String} name     フィルタ名
533 	 * @param {String} [x]      X 座標
534 	 * @param {String} [y]      Y 座標
535 	 * @param {String} [input]  入力
536 	 * @param {String} [result] 出力
537 	 */
538 	create: function(name, x, y, input, result) {
539 		var element = document.createElementNS(this.SVG_NS, name);
540 		if (x) element.setAttributeNS(null, "x", x);
541 		if (y) element.setAttributeNS(null, "y", y);
542 		if (input)  element.setAttributeNS(null, "in", input);
543 		if (result) element.setAttributeNS(null, "result", result);
544 		return element;
545 	}
546 };
547 /**
548  * SVG の feGaussianBlur 要素を管理します。
549  * @class
550  * @param {Number} stdDeviation 標準偏差
551  * @param {String} [x]      X 座標
552  * @param {String} [y]      Y 座標
553  * @param {String} [input]  入力
554  * @param {String} [result] 出力
555  */
556 SVGFilterPrimitives.GaussianBlur = function() {
557 	this.initialise.apply(this, arguments);
558 }
559 SVGFilterPrimitives.GaussianBlur.prototype = {
560 	/** 要素
561 	 * @type element
562 	 */
563 	element: null,
564 	/** コンストラクタから自動的に呼ばれ、初期化処理を行います。 */
565 	initialise: function(stdDeviation, x, y, input, result) {
566 		this.element = SVGFilterPrimitives.create("feGaussianBlur", x, y, input, result);
567 		this.element.setAttributeNS(null, "stdDeviation", stdDeviation);
568 	}
569 }