MediaWiki:GlyphEditor.js

Revision as of 00:00, 17 November 2015 by Jcblmaster (talk | contribs)

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
// 変数定義
var UNIT = 12;
var LEFT_MARGIN = 10 + UNIT/2;
var TOP_MARGIN  = 10 + UNIT/2;
var X_MARGIN = 5;
var Y_MARGIN = 5;
var MAX_X = 16;
var MAX_Y = 10;

var nodes    = new Array();
var branches = new Array();

var mouseX = -1;
var mouseY = -1;
var selectedIndex = 0;
var gridFlg     = 0;
var nodeIndex   = 0;
var branchIndex = 0;
var tmpBranch   = null;

var glyphIDs   = new Array('Glc','Gal','GlcNAc','GalNAc','GlcN','GalN','GlcA','GalA','Man','Rha','Ins','Fuc','Ara','Xyl','NeuA','NeuG','KDN','S','T','U','V','Erase');
var glyphChars = new Array('A',  'B',  'C',     'D',     'E',   'F',   'G',   'H',   'J',  'K',  'L',  'M',  'N',  'O',  'P',   'Q',   'R',  'S','T','U','V','');
// 初期処理
var initializeGlyphEditor = function()
{
	initCanvases();

	// 検索ボタン
	var searchURL = '/wiki/Volatile:StructureSearch';
	var searchButton = '{{{1}}}';
	if(searchButton.length > 0){
		var bt = document.createElement('input');
		bt.type  = 'button';
		bt.value = 'search';
		bt.onclick = function(){
			var string = getStructureString();
			window.open(searchURL + '?my_structure=' + string, "_blank");
		};
		document.getElementById(searchButton).appendChild(bt);
	}

	// ボタン
	for(var i = 0; i < glyphIDs.length; i ++)
		glyphPaint(glyphIDs[i], glyphChars[i], LEFT_MARGIN-1, TOP_MARGIN-1);
	glyphPaint('Cer',  'Z', LEFT_MARGIN/2,   TOP_MARGIN-1);
	glyphPaint('Sph',  'Y', LEFT_MARGIN/2,   TOP_MARGIN-1);
	glyphPaint('grid', '0', LEFT_MARGIN/2+1, TOP_MARGIN);

	glyphPaint('top_up',      'up',   UNIT+3, TOP_MARGIN-1);
	glyphPaint('bottom_up',   'up',   UNIT+3, TOP_MARGIN-1);
	glyphPaint('top_down',    'down', UNIT+3, TOP_MARGIN+1);
	glyphPaint('bottom_down', 'down', UNIT+3, TOP_MARGIN+1);
	glyphPaint('left',  'left',  UNIT+2, TOP_MARGIN-1);
	glyphPaint('right', 'right', UNIT+4, TOP_MARGIN-1);

	push(glyphIDs[0]);

	// イベント
	var canvas = document.getElementById('canvas');
	canvas.addEventListener('click', onClick, false);
	canvas.addEventListener('mousemove', onMousemove, false);
		// クリック
	function onClick(e) {
		var rect = e.target.getBoundingClientRect();
		var unit = ((Y_MARGIN)+UNIT);
		var x = Math.floor((e.clientX-rect.left-LEFT_MARGIN) / unit);
		var y = Math.floor((e.clientY-rect.top -TOP_MARGIN)  / unit);
		if(x >= MAX_X-2 || y >= MAX_Y-1)
			return;
		if(selectedIndex == glyphIDs.length-1){ // 消しゴム
			if(removeJudge(x, y)){
				for(var i = 1; i < nodes.length; i ++){
					var node = nodes[i];
					if(node.x == x && node.y == y){
						// 枝の削除
						for(var j = 0; j < branches.length; j ++){
							var branch = branches[j];
							if(branch.n1 == i || branch.n2 == i){
								branches.splice(j, 1);
								break;
							}
						}
						// 枝インデックスの修正
						for(var j = 0; j < branches.length; j ++){
							var branch = branches[j];
							if(branch.n1 > i)
								branch.n1 --;
							if(branch.n2 > i)
								branch.n2 --;
						}
						// ノードの削除
						nodes.splice(i, 1);
						nodeIndex   --;
						branchIndex --;
						tmpBranch = null;
						break;
					}
				}
			}
		} else {
			var res = addJudge(x, y);
			if(res == -1)
				return;
			var found = false;
			for(var i = 1; i < nodes.length; i ++){
				var node = nodes[i];
				if(node.x == x && node.y == y){
					found = true;
					node.type = glyphChars[selectedIndex];
	//				branches[branchIndex++] = new Branch(nodes.indexOf(res), i);
					break;
				}
			}
			if(!found){
				nodes[nodeIndex++]      = new Node(glyphChars[selectedIndex], x, y);
				branches[branchIndex++] = new Branch(res, nodeIndex-1);
			}
		}
		canvasPaint();
	}
		// マウスムーブ
	function onMousemove(e) {
		var rect = e.target.getBoundingClientRect();
		var unit = ((Y_MARGIN)+UNIT);
		var x = Math.floor((e.clientX-rect.left-LEFT_MARGIN) / unit);
		var y = Math.floor((e.clientY-rect.top -TOP_MARGIN)  / unit);
		if(selectedIndex == glyphIDs.length-1){ // 消しゴム
			if(removeJudge(x, y)){
				mouseX = x;
				mouseY = y;
			} else
				mouseY = mouseY = -1;
			tmpBranch = null;
		} else { // 糖
			var res = addJudge(x, y);
			if(res != -1){
				mouseX = x;
				mouseY = y;
				tmpBranch = new Branch(res, nodeIndex);
			} else {//if(x >= MAX_X-2 || y >= MAX_Y-1){
				mouseX    = mouseY = -1;
				tmpBranch = null;
			}
		}
		canvasPaint();
	}

	nodes[nodeIndex++] = new Node('Z', MAX_X-2, MAX_Y/2-1);
	switchGrid();
	baseChange('Cer','Sph');
}
function initCanvases()
{
	var canvas = document.createElement('canvas');
	canvas.id    = 'canvas';
	canvas.width  = 291;
	canvas.height = 185;
	document.getElementById('td_canvas').appendChild(canvas);

	// upper button
	var items1 = ['top_up', 'top_down'];
	for(var i = 0; i < items1.length; i ++){
		var bt = document.createElement('canvas');
		bt.id    = items1[i];
		bt.width = bt.height = 30;
		bt.setAttribute('class', 'button');
		bt.style.cssText = 'border: outset 3px gray;';
		if(i == 0)
			bt.onclick = function(){changeTop(-1)};
		else
			bt.onclick = function(){changeTop(1)};
		document.getElementById('td_top').appendChild(bt);
	}

	// middle button
	var items2 = ['left', 'right'];
	for(var i = 0; i < items2.length; i ++){
		var bt = document.createElement('canvas');
		bt.id    = items2[i];
		bt.width = bt.height = 30;
		bt.setAttribute('class', 'button');
		bt.style.cssText = 'border: outset 3px gray;';
		if(i == 0)
			bt.onclick = function(){changeLeft(-1)};
		else
			bt.onclick = function(){changeLeft(1)};
		document.getElementById('td_middle').appendChild(bt);
		document.getElementById('td_middle').appendChild(document.createElement('br'));
	}

	// bottom button
	var items3 = ['bottom_up', 'bottom_down'];
	for(var i = 0; i < items3.length; i ++){
		var bt = document.createElement('canvas');
		bt.id    = items3[i];
		bt.width = bt.height = 30;
		bt.setAttribute('class', 'button');
		bt.style.cssText = 'border: outset 3px gray;';
		if(i == 0)
			bt.onclick = function(){changeBottom(-1)};
		else
			bt.onclick = function(){changeBottom(1)};
		document.getElementById('td_bottom').appendChild(bt);
	}

	// base button
	var items4 = ['Cer', 'Sph'];
	for(var i = 0; i < items4.length; i ++){
		var bt = document.createElement('canvas');
		bt.id    = items4[i];
		bt.width = bt.height = 30;
		bt.setAttribute('class', 'button');
		if(i == 0)
			bt.onclick = function(){baseChange(items4[0],items4[1])};
		else
			bt.onclick = function(){baseChange(items4[1],items4[0])};
		document.getElementById('td_'+items4[i]).appendChild(bt);
	}

	{ // grid button
		var bt = document.createElement('canvas');
		bt.id    = 'grid';
		bt.width = bt.height = 30;
		bt.setAttribute('class', 'button');
		bt.onclick = function(){switchGrid();};
		document.getElementById('td_grid').appendChild(bt);
	}

	var items5 = ['Glc','Gal','GlcNAc','GalNAc','GlcN','GalN','GlcA','GalA','Man','Rha','Ins',
			'Fuc','Ara','Xyl','NeuA','NeuG','KDN','S','T','U','V','Erase'];
	for(var i = 0; i < items5.length; i ++){
		var bt = document.createElement('canvas');
		bt.id    = items5[i];
		bt.width = bt.height = 30;
		bt.setAttribute('class', 'button');
		bt.onclick = function(){push(this.id)};
		document.getElementById('td_'+items5[i]).appendChild(bt);
	}
}
// 糖追加の判断
// nodesインデックス、見つからなければ-1
function addJudge(x,y)
{
	if(x < 0 || y < 0 || y >= MAX_Y-1)
		return -1;

	// 真横の判定
	for(var i = 0; i < nodes.length; i ++){
		var node = nodes[i];
		if(node.x == x+1 && node.y == y)
			return i;
	}
	// 斜めの判定
	var index = -1;
	var distance = 99;
	for(var i = 0; i < nodes.length; i ++){
		var node = nodes[i];
		if(node.x == x+1 && i != 0){ // 右のどこか
			var d = Math.abs(node.y-y);
			if(d < distance){ // 最短距離のものを探し出す
				index = i;
				distance = d;
			}
		}
	}
	return index;
}
// 糖削除の判断
function removeJudge(x,y)
{
	// 真横の判定
	for(var i = 1; i < nodes.length; i ++){
		var node = nodes[i];
		if(node.x == x && node.y == y){
			var count = 0;
			for(var j = 0; j < branches.length; j ++){
				var branch = branches[j];
				if(branch.n1 == i || branch.n2 == i)
					count ++;
			}
			if(count == 1) // 連結線が一つだけなら削除可能
				return true;
		}
	}
	return false;
}
// ボタン押下
function baseChange(nid,pid)
{
	var button;

	button = document.getElementById(pid);
	button.style.border = 'outset 3px gray';
	button.style.backgroundColor = 'white';

	button = document.getElementById(nid);
	button.style.border = 'inset 3px gray';
	button.style.backgroundColor = 'lightgray';

	if(nid == "Cer")
		nodes[0].type = 'Z';
	else
		nodes[0].type = 'Y';
	canvasPaint();
}
// グリフ描画
function glyphPaint(id, glyph, leftMargin, topMargin)
{
	var cn = document.getElementById(id);
	var node = new Node(glyph, 0, 0);
	node.paint(cn.getContext('2d'), leftMargin, topMargin);
}
// グリッドの表示/非表示の切り替え
function switchGrid()
{
	gridFlg = 1 - gridFlg;
	button = document.getElementById('grid');
	if(gridFlg == 1){
		button.style.border = 'inset 3px gray';
		button.style.backgroundColor = 'lightgray';
	} else {
		button.style.border = 'outset 3px gray';
		button.style.backgroundColor = 'white';
	}

	canvasPaint();
}
function canvasPaint()
{
	// 準備
	var tmpNodes = new Array();
	for(var i = 0; i < nodes.length; i ++)
		tmpNodes[i] = nodes[i];
	if(mouseX >= 0 && mouseY >= 0)
		tmpNodes[nodeIndex] = new Node(glyphChars[selectedIndex], mouseX, mouseY);

	var canvas = document.getElementById('canvas');
	var g = canvas.getContext('2d');

	g.clearRect(0, 0, 360, 360);
	g.fillStyle = 'white';
	g.rect(0, 0, 360, 360);
	g.fill();

	var unit = Y_MARGIN+UNIT;
	if(gridFlg == 1){
		// 枠
		g.strokeStyle = 'lightgray';
		for(var i = 0; i < MAX_Y; i ++){
			var y = i * unit + TOP_MARGIN;

			g.beginPath();
			g.moveTo(LEFT_MARGIN, y);
			g.lineTo(unit*(MAX_X), y);
			g.stroke();

			for(var j = 0; j < MAX_X-1; j ++){
				var x = j * unit + LEFT_MARGIN;

				g.beginPath();
				g.moveTo(x, TOP_MARGIN);
				g.lineTo(x, unit*(MAX_Y));
				g.stroke();
			}
		}
	}

	// 線とグリフ
	for(var i = 0; i < branches.length; i ++)
		branches[i].paint(g);
	if(tmpBranch != null)
		tmpBranch.tmpPaint(g, tmpNodes[tmpNodes.length-1]);

	for(var i = 0; i < tmpNodes.length; i ++)
		tmpNodes[i].paint(g, LEFT_MARGIN+UNIT/1.5+1, TOP_MARGIN+UNIT/1.5+1 );
//		tmpNodes[i].paint(g, UNIT/1.5+1, UNIT/1.5+1);

	if(mouseX >= 0 && mouseY >= 0){
		g.beginPath();
		g.strokeStyle = 'red';
		g.rect(mouseX*((X_MARGIN)+UNIT)+LEFT_MARGIN, mouseY*((Y_MARGIN)+UNIT)+TOP_MARGIN, UNIT+Y_MARGIN, UNIT+X_MARGIN);
		g.stroke();
	}
}
// ボタン押下
function push(id)
{
	var button;
	for(var i = 0; i < glyphIDs.length; i ++){
		button = document.getElementById(glyphIDs[i]);
		button.style.border = 'outset 3px gray';
		button.style.backgroundColor = 'white';
	}
	button = document.getElementById(id);
	button.style.border = 'inset 3px gray';
	button.style.backgroundColor = 'lightgray';

	selectedIndex = glyphIDs.indexOf(id);
}
// 上部にラインを追加/削除する
function changeTop(direction)
{
	if(direction == 1){ // ライン追加
		for(var i = 0; i < nodes.length; i ++)
			nodes[i].y ++;
		MAX_Y ++;

	} else if(direction == -1){ // ライン削除
		for(var i = 0; i < nodes.length; i ++){ // 削除不可
			if(nodes[i].y == 0)
				return;
		}
		for(var i = 0; i < nodes.length; i ++)
			nodes[i].y --;
		MAX_Y --;
	}

	var canvas = document.getElementById("canvas");
	canvas.height += direction * (UNIT+Y_MARGIN);

	canvasPaint();
}
// 下部にラインを追加/削除する
function changeBottom(direction)
{
	if(direction == 1){ // ライン追加
		MAX_Y ++;

	} else if(direction == -1){ // ライン削除
		for(var i = 0; i < nodes.length; i ++){ // 削除不可
			if(nodes[i].y == MAX_Y-2)
				return;
		}
		MAX_Y --;
	}

	var canvas = document.getElementById("canvas");
	canvas.height += direction * (UNIT+Y_MARGIN);

	canvasPaint();
}
// 左にラインを追加/削除する
function changeLeft(direction)
{
	if(direction == 1){ // ライン追加
		for(var i = 0; i < nodes.length; i ++)
			nodes[i].x ++;
		MAX_X ++;

	} else if(direction == -1){ // ライン削除
		for(var i = 0; i < nodes.length; i ++){ // 削除不可
			if(nodes[i].x == 0)
				return;
		}
		for(var i = 0; i < nodes.length; i ++)
			nodes[i].x --;
		MAX_X --;
	}

	var canvas = document.getElementById("canvas");
	canvas.width += direction * (UNIT+X_MARGIN);

	canvasPaint();
}
//// ノードクラスの作成 /////////////////////////////////////////////////
var Node = function(type, x, y){
	this.type = type;
	this.x = x;
	this.y = y;
}
/// メソッドの定義 //////////////////////////////////////////////////
Node.prototype.drawString = function(g, str, x, y){
	g.beginPath();
	g.strokeStyle = 'white';
	g.fillStyle = 'white';
	g.rect(x-UNIT/2, y-UNIT/2, UNIT, UNIT);
	g.fill();

	g.fillStyle = 'black';
	g.font = UNIT + "px 'Arial'";
	var met;
	if(str.length == 1)
		met = g.measureText(str);
	else
		met = g.measureText(str.substring(0, 1));
	g.fillText(str, x-met.width/2, y+UNIT/3);
	g.stroke();
}
Node.prototype.drawRectangle = function(g, color, x, y){
	g.beginPath();
	g.fillStyle = color;
	g.rect(x-UNIT/2, y-UNIT/2, UNIT, UNIT);
	g.fill();
	g.stroke();
}
Node.prototype.drawSeparatedRectangle = function(g, color1, color2, x, y){
	g.beginPath();
	g.fillStyle = color1;
	g.moveTo(x-UNIT/2, y-UNIT/2);
	g.lineTo(x+UNIT/2, y-UNIT/2);
	g.lineTo(x+UNIT/2, y+UNIT/2);
	g.closePath();
	g.fill();
	g.stroke();

	g.beginPath();
	g.fillStyle = color2;
	g.moveTo(x-UNIT/2, y-UNIT/2);
	g.lineTo(x-UNIT/2, y+UNIT/2);
	g.lineTo(x+UNIT/2, y+UNIT/2);
	g.closePath();
	g.fill();
	g.stroke();
}
Node.prototype.drawCircle = function(g, color, x, y){
	g.beginPath();
	g.fillStyle = color;
	g.arc(x, y, UNIT/2, 0, Math.PI*2, false);
	g.fill();
	g.stroke();
}
Node.prototype.drawTriangle = function(g, color, x, y){
	g.beginPath();
	g.fillStyle = color;
	g.moveTo(x-UNIT/2, y+UNIT/2);
	g.lineTo(x+UNIT/2, y+UNIT/2);
	g.lineTo(x       , y-UNIT/2);
	g.closePath();
	g.fill();
	g.stroke();
}
Node.prototype.drawStar = function(g, color, x, y){
	g.beginPath();
	g.fillStyle = color;
	g.moveTo(x       , y-UNIT/2);
	g.lineTo(x+UNIT/6, y-UNIT/7);
	g.lineTo(x+UNIT/2, y-UNIT/7);
	g.lineTo(x+UNIT/5, y+UNIT/10);
	g.lineTo(x+UNIT/3, y+UNIT/2);
	g.lineTo(x       , y+UNIT/4);

	g.lineTo(x-UNIT/3, y+UNIT/2);
	g.lineTo(x-UNIT/5, y+UNIT/10);
	g.lineTo(x-UNIT/2, y-UNIT/7);
	g.lineTo(x-UNIT/6, y-UNIT/7);

	g.closePath();
	g.fill();
	g.stroke();
}
Node.prototype.drawVerticalSeparatedPentagon = function(g, color1, color2, x, y){
	g.beginPath();
	g.fillStyle = color1;
	g.moveTo(x       , y-UNIT/2);
	g.lineTo(x-UNIT/2, y-UNIT/7);
	g.lineTo(x-UNIT/3, y+UNIT/2);
	g.lineTo(x,        y+UNIT/2);
	g.closePath();
	g.fill();
	g.stroke();

	g.beginPath();
	g.fillStyle = color2;
	g.moveTo(x,        y-UNIT/2);
	g.lineTo(x+UNIT/2, y-UNIT/7);
	g.lineTo(x+UNIT/3, y+UNIT/2);
	g.lineTo(x,        y+UNIT/2);
	g.closePath();
	g.fill();
	g.stroke();
}
Node.prototype.drawDiamond = function(g, color, x, y){
	g.beginPath();
	g.fillStyle = color;
	g.moveTo(x-UNIT/2, y);
	g.lineTo(x       , y-UNIT/2);
	g.lineTo(x+UNIT/2, y);
	g.lineTo(x       , y+UNIT/2);
	g.closePath();
	g.fill();
	g.stroke();
}
Node.prototype.drawDiamondWithPattern = function(g, color, x, y){

	g.save();

	g.beginPath();
	g.fillStyle = color;
	g.moveTo(x-UNIT/2, y);
	g.lineTo(x       , y-UNIT/2);
	g.lineTo(x+UNIT/2, y);
	g.lineTo(x       , y+UNIT/2);
	g.closePath();
	g.fill();
	g.clip();

	g.strokeStyle = 'white';
	g.beginPath();
	for(var i = x-UNIT/2; i < x+UNIT/2; i += 4){
		g.moveTo(i, y-UNIT/2);
		g.lineTo(i, y+UNIT/2);
	}
	for(var i = y-UNIT/2; i < y+UNIT/2; i += 4){
		g.moveTo(x-UNIT/2, i);
		g.lineTo(x+UNIT/2, i);
	}
	g.stroke();

	g.strokeStyle = 'black';
	g.beginPath();
	g.moveTo(x-UNIT/2, y);
	g.lineTo(x       , y-UNIT/2);
	g.lineTo(x+UNIT/2, y);
	g.lineTo(x       , y+UNIT/2);
	g.closePath();
	g.stroke();

	g.restore();
}
Node.prototype.drawHorizontalSeparatedDiamond = function(g, color1, color2, x, y){
	g.beginPath();
	g.fillStyle = color1;
	g.moveTo(x-UNIT/2, y);
	g.lineTo(x       , y-UNIT/2);
	g.lineTo(x+UNIT/2, y);
	g.closePath();
	g.fill();
	g.stroke();
	g.beginPath();
	g.fillStyle = color2;
	g.moveTo(x-UNIT/2, y);
	g.lineTo(x       , y+UNIT/2);
	g.lineTo(x+UNIT/2, y);
	g.fill();
	g.stroke();
}
Node.prototype.drawVerticalSeparatedDiamond = function(g, color1, color2, x, y){
	g.beginPath();
	g.fillStyle = color1;
	g.moveTo(x       , y-UNIT/2);
	g.lineTo(x-UNIT/2, y);
	g.lineTo(x       , y+UNIT/2);
	g.closePath();
	g.fill();
	g.stroke();
	g.beginPath();
	g.fillStyle = color2;
	g.moveTo(x       , y-UNIT/2);
	g.lineTo(x+UNIT/2, y);
	g.lineTo(x       , y+UNIT/2);
	g.fill();
	g.stroke();
}
Node.prototype.drawGrid = function(g, x, y){
	g.beginPath();
	g.strokeStyle = 'black';
	g.moveTo(x-UNIT/2, y-UNIT/2);
	g.lineTo(x-UNIT/2+UNIT*2, y-UNIT/2);
	g.moveTo(x-UNIT/2, y+UNIT/2);
	g.lineTo(x-UNIT/2+UNIT*2, y+UNIT/2);
	g.moveTo(x-UNIT/2+UNIT/2, y-UNIT);
	g.lineTo(x-UNIT/2+UNIT/2, y-UNIT/2+UNIT*1.5);
	g.moveTo(x-UNIT/2+UNIT*1.5, y-UNIT);
	g.lineTo(x-UNIT/2+UNIT*1.5, y-UNIT/2+UNIT*1.5);
	g.stroke();
}
Node.prototype.drawErace = function(g, x, y){
	g.beginPath();
	g.strokeStyle = 'white';
	g.fillStyle   = 'white';
	g.rect(x-UNIT/2, y-UNIT/2, UNIT, UNIT);
	g.fill();
	g.stroke();
}
Node.prototype.drawUp = function(g, x, y){
	g.beginPath();
	g.fillStyle = 'green';
	g.moveTo(x-UNIT, y+UNIT/2);
	g.lineTo(x+UNIT, y+UNIT/2);
	g.lineTo(x     , y-UNIT/2);
	g.closePath();
	g.fill();
	g.stroke();
}
Node.prototype.drawDown = function(g, x, y){
	g.beginPath();
	g.fillStyle = 'green';
	g.moveTo(x-UNIT, y-UNIT/2);
	g.lineTo(x+UNIT, y-UNIT/2);
	g.lineTo(x     , y+UNIT/2);
	g.closePath();
	g.fill();
	g.stroke();
}
Node.prototype.drawLeft = function(g, x, y){
	g.beginPath();
	g.fillStyle = 'green';
	g.moveTo(x+UNIT/2, y-UNIT);
	g.lineTo(x+UNIT/2, y+UNIT);
	g.lineTo(x-UNIT/2, y);
	g.closePath();
	g.fill();
	g.stroke();
}
Node.prototype.drawRight = function(g, x, y){
	g.beginPath();
	g.fillStyle = 'green';
	g.moveTo(x-UNIT/2, y-UNIT);
	g.lineTo(x-UNIT/2, y+UNIT);
	g.lineTo(x+UNIT/2, y);
	g.closePath();
	g.fill();
	g.stroke();
}
Node.prototype.paint = function(g, leftMargin, topMargin){
	var drawx = this.x * (UNIT+X_MARGIN) + leftMargin;
	var drawy = this.y * (UNIT+Y_MARGIN) + topMargin;
	g.strokeStyle = 'black';

	if(this.type == 'A'){ // 青●
		this.drawCircle(g, '#0000FA', drawx, drawy);

	} else if(this.type == 'B'){ // 黄●
		this.drawCircle(g, 'yellow', drawx, drawy);

	} else if(this.type == 'C'){ // 青■
		this.drawRectangle(g, '#0000FA', drawx, drawy);

	} else if(this.type == 'D'){ // 黄■
		this.drawRectangle(g, 'yellow', drawx, drawy);

	} else if(this.type == 'E'){ // 半分青□
		this.drawSeparatedRectangle(g, '#0000FA', 'white', drawx, drawy);

	} else if(this.type == 'F'){ // 半分黄□
		this.drawSeparatedRectangle(g, 'yellow', 'white', drawx, drawy);

	} else if(this.type == 'G'){ // GlcA 上半分青◆
		this.drawHorizontalSeparatedDiamond(g, 'blue', 'white', drawx, drawy);

	} else if(this.type == 'H'){ // GalA 右半分黄◆
		this.drawVerticalSeparatedDiamond(g, 'yellow', 'white', drawx, drawy);

	} else if(this.type == 'J'){ // Man 緑●
			this.drawCircle(g, '#00C832', drawx, drawy);

	} else if(this.type == 'K'){ // 灰色△
		this.drawTriangle(g, 'lightgray', drawx, drawy);

	} else if(this.type == 'L'){ // Ins I
		this.drawString(g, 'I', drawx, drawy);

	} else if(this.type == 'M'){ // 赤△
		this.drawTriangle(g, '#FA0000', drawx, drawy);

	} else if(this.type == 'N'){ // 左半分青の五角形
		this.drawVerticalSeparatedPentagon(g, '#C8FAFA', 'white', drawx, drawy);

	} else if(this.type == 'O'){ // オレンジ★
		this.drawStar(g, '#FA6400', drawx, drawy);

	} else if(this.type == 'P'){ // 赤色◆
		this.drawDiamond(g, '#FA0000', drawx, drawy);

	} else if(this.type == 'Q'){ // 水色◆
		this.drawDiamond(g, '#C8FAFA', drawx, drawy);

	} else if(this.type == 'R'){ // 緑色◆
		this.drawDiamond(g, '#00FA00', drawx, drawy);

	} else if(this.type == 'S'){ //
		this.drawString(g, 'P', drawx, drawy);

	} else if(this.type == 'T'){ //
		this.drawString(g, 'E', drawx, drawy);

	} else if(this.type == 'U'){ //
		this.drawString(g, 'S', drawx, drawy);

	} else if(this.type == 'V'){ //
		this.drawString(g, 'R', drawx, drawy);

	} else if(this.type == 'W'){ //
		this.drawString(g, 'R', drawx, drawy);

	} else if(this.type == 'X'){ //
		this.drawString(g, 'C', drawx, drawy);

	} else if(this.type == 'Y'){
		this.drawString(g, 'Sph', drawx, drawy); 

	} else if(this.type == 'Z'){
		this.drawString(g, 'Cer', drawx, drawy);

	// 特殊
	} else if(this.type == '0'){
		this.drawGrid(g, drawx, drawy);

	} else if(this.type == ''){
		this.drawErace(g, drawx, drawy);

	// 矢印
	} else if(this.type == 'up'){
		this.drawUp(g, drawx, drawy);

	} else if(this.type == 'down'){
		this.drawDown(g, drawx, drawy);

	} else if(this.type == 'left'){
		this.drawLeft(g, drawx, drawy);

	} else if(this.type == 'right'){
		this.drawRight(g, drawx, drawy);
	}
};
//// 枝クラスの定義 ///////////////////////////////////////////////
var Branch = function(n1, n2){
	this.n1 = n1;//-1;
	this.n2 = n2;//-1;
}
/// メソッドの定義 //////////////////////////////////////////////////
Branch.prototype.paint = function(g){
	this.p(g, nodes[this.n1], nodes[this.n2]);
/*	var x1 = nodes[this.n1].x * (UNIT+X_MARGIN) + LEFT_MARGIN+1 + UNIT/2+2;
	var y1 = nodes[this.n1].y * (UNIT+Y_MARGIN) + TOP_MARGIN+1 + UNIT/2+2;
	var x2 = nodes[this.n2].x * (UNIT+X_MARGIN) + LEFT_MARGIN+1 + UNIT/2+2;
	var y2 = nodes[this.n2].y * (UNIT+Y_MARGIN) + TOP_MARGIN+1 + UNIT/2+2;

	g.beginPath();
	g.strokeStyle = 'black';
	g.moveTo(x1, y1);
	g.lineTo(x2, y2);
	g.stroke();*/
}
Branch.prototype.tmpPaint = function(g,tmpNode){
	this.p(g, nodes[this.n1], tmpNode);
/*	var x1 = nodes[this.n1].x * (UNIT+X_MARGIN) + LEFT_MARGIN+1 + UNIT/2+2;
	var y1 = nodes[this.n1].y * (UNIT+Y_MARGIN) + TOP_MARGIN+1 + UNIT/2+2;
	var x2 = tmpNode.x * (UNIT+X_MARGIN) + LEFT_MARGIN+1 + UNIT/2+2;
	var y2 = tmpNode.y * (UNIT+Y_MARGIN) + TOP_MARGIN+1 + UNIT/2+2;

	g.beginPath();
	g.strokeStyle = 'black';
	g.moveTo(x1, y1);
	g.lineTo(x2, y2);
	g.stroke();*/
}
Branch.prototype.p = function(g,node1,node2){
	var x1 = node1.x * (UNIT+X_MARGIN) + LEFT_MARGIN+1 + UNIT/2+2;
	var y1 = node1.y * (UNIT+Y_MARGIN) + TOP_MARGIN+1  + UNIT/2+2;
	var x2 = node2.x * (UNIT+X_MARGIN) + LEFT_MARGIN+1 + UNIT/2+2;
	var y2 = node2.y * (UNIT+Y_MARGIN) + TOP_MARGIN+1  + UNIT/2+2;

	g.beginPath();
	g.strokeStyle = 'black';
	g.moveTo(x1, y1);
	g.lineTo(x2, y2);
	g.stroke();
}
// 検索用
function getStructureString()
{
	var baseX = 0;
	var baseY = 0;
	for(var i = 0; i < nodes.length; i ++){
		if(nodes[i].type == 'Z' || nodes[i].type == 'Y'){
			baseX = nodes[i].x;
			baseY = nodes[i].y;
			break;
		}
	}

	// ソート
	var tmp = new Array();
	for(var i = 0; i < nodes.length; i ++)
		tmp[i] = nodes[i];
	tmp.sort(function compare(n1, n2){
		if(n1.y < n2.y)
			return -1;
		if(n1.y > n2.y)
			return 1;
		if(n1.x < n2.x)
			return -1;
		if(n1.x > n2.x)
			return 1;
		return 0;
	});

	// クエリ作成
	var str = 'Cfg=%';
	var prev = tmp[0].y;
	for(var i = 0; i < tmp.length; i ++){
		if(prev != tmp[i].y){
			str += '%';
			prev = tmp[i].y;
		}
		str += tmp[i].toString(baseX, baseY);
	}
	str += '%';
/*
	str += '%';
	for(var i = 0; i < branches.length; i ++)
		str += branches[i].toString();
*/
	return str;
}
Node.prototype.toString = function(baseX, baseY)
{
	return ' ' + this.type + ' ' + (baseX-this.x) + ' ' + (this.y-baseY) + ';';
}
Branch.prototype.toString = function()
{
	return ' ' + this.n1 + ' ' + this.n2 + ';';
}
// ロード時の処理
if( window.addEventListener )
  window.addEventListener("load", initializeGlyphEditor, false);
else
  setTimeout(t, 100);