Created
February 2, 2012 03:11
-
-
Save aya-eiya/1721182 to your computer and use it in GitHub Desktop.
HTML5のCanvasの練習です。テキストエリアの文字をCanvasに表示します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html /> | |
<html> | |
<head> | |
<title>1_howToPutCharToCanvas.html</title> | |
<style> | |
canvas#vwrMain{ | |
border:1px solid black; | |
} | |
div#main{ | |
margin:5px; | |
} | |
</style> | |
<script> | |
function nameSpace(glb,spc){ | |
var ns = spc.split('.'); | |
var spcs = glb; | |
for(var i=0;i<ns.length;i++){ | |
spcs = spcs[ns[i]] = new Object(); | |
} | |
return spcs; | |
} | |
(function(global,_$){ | |
_$.textCanvas = function(canvasId){ | |
this.Canvas = global.document.getElementById(canvasId); | |
this.putChar = function(val){ | |
var _cxt = this.Canvas.getContext("2d"); | |
_cxt.clearRect(0,0,300,300); | |
_cxt.font = "20pt Arial"; | |
_cxt.fillText(val, 10, 50); | |
} | |
} | |
})( | |
this, | |
nameSpace(this,'aya.eiya.test') | |
); | |
</script> | |
</head> | |
<body> | |
<h1>Canvasに文字を打ち込む</h1> | |
<p>HTML5のCanvasの練習です。テキストエリアの文字をCanvasに表示します。</p> | |
<div id="main"> | |
<canvas id="vwrMain"></canvas> | |
</div> | |
<form> | |
<input type="text" onkeyup="(new aya.eiya.test.textCanvas('vwrMain')).putChar(this.value);" /> | |
</form> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html /> | |
<html> | |
<head> | |
<title>2_howToWriteVerticallyToCanvas.html</title> | |
<style> | |
canvas#vwrMain{ | |
border:1px solid black; | |
} | |
div#main{ | |
margin:5px; | |
} | |
</style> | |
<script> | |
function nameSpace(glb,spc){ | |
var ns = spc.split('.'); | |
var spcs = glb; | |
for(var i=0;i<ns.length;i++){ | |
spcs = spcs[ns[i]] = new Object(); | |
} | |
return spcs; | |
} | |
(function(global,_$){ | |
_$.textCanvas = function(canvasId){ | |
this.Canvas = global.document.getElementById(canvasId); | |
this.Canvas.width = 300; | |
this.Canvas.height = 300; | |
this.fontSize = 20; | |
this.putCharVertically = function(val){ | |
var _cxt = this.Canvas.getContext("2d"); | |
var hp = 0; | |
var hps = 0; | |
var vp = 0; | |
var vps = 0; | |
var chr = ''; | |
_cxt.clearRect(0,0,300,300); | |
_cxt.font = this.fontSize+"px Arial"; | |
for(var i=0;i<val.length;i++){ | |
chr = val.charAt(i); | |
if( chr.match(/[、。]/) ){ | |
hp = 0; | |
}else{ | |
hp = _cxt.measureText(chr).width; | |
} | |
vp = this.fontSize; | |
_cxt.fillText(chr, 260 - hps + this.fontSize - hp/2 , this.fontSize + vps ); | |
vps = vps + vp; | |
if(vps > this.Canvas.height - this.fontSize*2){ | |
hps += this.fontSize; | |
vps = 0; | |
} | |
} | |
} | |
} | |
})( | |
this, | |
nameSpace(this,'aya.eiya.test') | |
); | |
</script> | |
</head> | |
<body onload="cvs = new aya.eiya.test.textCanvas('vwrMain');cvs.putCharVertically(document.getElementById('inMain').value);"> | |
<h1>Canvasに縦書きで文字を打ち込む</h1> | |
<p>HTML5のCanvasの練習です。テキストエリアの文字を縦書きでCanvasに表示します。</p> | |
<p>禁則処理および字の縦方向の大きさは考慮されません。</p> | |
<div id="main"> | |
<canvas id="vwrMain"></canvas> | |
</div> | |
<form> | |
<input type="text" id="inMain" onkeyup="cvs.putCharVertically(this.value);" value="HTML5のCanvasの練習です。テキストエリアの文字を縦書きでCanvasに表示します。" /> | |
</form> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html /> | |
<html> | |
<head> | |
<title>3_howToSelectVerticalTextFromCanvas.html</title> | |
<style> | |
canvas#vwrMain{ | |
border:1px solid black; | |
} | |
div#main{ | |
margin:5px; | |
} | |
</style> | |
<script> | |
//nameSpace | |
function nameSpace(glb,spc){ | |
var ns = spc.split('.'); | |
var spcs = glb; | |
for(var i=0;i<ns.length;i++){ | |
spcs = spcs[ns[i]] = new Object(); | |
} | |
return spcs; | |
} | |
(function(global,_$){ | |
_$.textCanvas = function(canvasId){ | |
this.Canvas = global.document.getElementById(canvasId); | |
this.Canvas.width = 300; | |
this.Canvas.height = 300; | |
this.fontSize = 20; | |
this.charPointMap = new Array(); | |
this.text = ""; | |
this.putCharVertically = function(val){ | |
var _cxt = this.Canvas.getContext("2d"); | |
var hp = 0; | |
var hps = 0; | |
var vp = 0; | |
var vps = 0; | |
var chr = ''; | |
var stx = 0; | |
this.text = val; | |
_cxt.clearRect(0,0,300,300); | |
_cxt.font = this.fontSize+"px Arial"; | |
this.charPointMap = new Array(); | |
for(var i=0;i<val.length;i++){ | |
chr = val.charAt(i); | |
if( chr.match(/[、。]/) ){ | |
hp = 0; | |
}else{ | |
hp = _cxt.measureText(chr).width; | |
} | |
vp = this.fontSize; | |
stx = 260 - hps; | |
sty = this.fontSize + vps; | |
if( | |
( this._selectArea.st <= i && i <=this._selectArea.ed ) | |
|| | |
( this._selectArea.ed <= i && i <=this._selectArea.st ) | |
) | |
{ | |
_cxt.strokeStyle = "blue"; | |
_cxt.fillStyle = "blue"; | |
}else{ | |
_cxt.strokeStyle = "black"; | |
_cxt.fillStyle = "black"; | |
} | |
_cxt.fillText(chr, stx + this.fontSize - hp/2, sty ); | |
this.charPointMap[this.charPointMap.length]=( | |
function(stx,sty,size,c){ | |
return function(x,y){ | |
return (stx+size/2 <= x && x <= stx+size*3/2 && sty-size <= y && y <= sty)?c:-1; | |
}; | |
})(stx,sty,this.fontSize,i); | |
vps = vps + vp; | |
if(vps > this.Canvas.height - this.fontSize*2){ | |
hps += this.fontSize; | |
vps = 0; | |
} | |
} | |
} | |
this._selectArea={st:-1,ed:-1}; | |
this.Canvas.onmouseup = ( | |
function(parent){ | |
return function(e1){ | |
var st,ed; | |
parent.Canvas.onmousemove = function(e2){}; | |
if(parent._selectArea.st >= 0){ | |
if(parent._selectArea.st < parent._selectArea.ed){ | |
st = parent._selectArea.st; | |
ed = parent._selectArea.ed+1; | |
}else{ | |
st = parent._selectArea.ed; | |
ed = parent._selectArea.st+1; | |
} | |
alert(parent.text.substring(st,ed)); | |
console.log(parent.text.substring(st,ed)); | |
} | |
parent._selectArea={st:-1,ed:-1}; | |
parent.putCharVertically(parent.text); | |
} | |
})(this); | |
this.selectText = function(num){ | |
if(num < 0) return; | |
if(this._selectArea.st < 0) | |
this._selectArea.st = num; | |
this._selectArea.ed = num; | |
} | |
this.Canvas.onmousedown =( | |
function(parent){ | |
return function(e1){ | |
parent.selectText(_getCharPointFromMousePosition(e1,parent)); | |
parent.Canvas.onmousemove = function(e2){ | |
parent.putCharVertically(parent.text); | |
parent.selectText(_getCharPointFromMousePosition(e2,parent)); | |
} | |
} | |
} | |
)(this); | |
_getCharPointFromMousePosition = function(e,parent){ | |
var rect = e.target.getBoundingClientRect(); | |
var x = e.clientX - rect.left; | |
var y = e.clientY - rect.top; | |
var hits=parent.charPointMap; | |
var hit=-1; | |
for(var i=0;i<hits.length;i++){ | |
hit = hits[i](x,y); | |
if(hit>=0){ | |
return hit; | |
} | |
} | |
return -1; | |
}; | |
} | |
})( | |
this, | |
nameSpace(this,'aya.eiya.test') | |
); | |
</script> | |
</head> | |
<body onload="cvs = new aya.eiya.test.textCanvas('vwrMain');cvs.putCharVertically(document.getElementById('inMain').value);"> | |
<h1>Canvasの縦書きの文字を選択する</h1> | |
<p>HTML5のCanvasの練習です。Canvasに表示された縦書きの文字を選択します。</p> | |
<p>文字列のドラッグした範囲をアラートで表示します。</p> | |
<div id="main"> | |
<canvas id="vwrMain"></canvas> | |
</div> | |
<form> | |
<input type="text" id="inMain" onkeyup="cvs.putCharVertically(this.value);" value="HTML5のCanvasの練習です。テキストエリアの文字を縦書きでCanvasに表示します。" /> | |
</form> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html /> | |
<html> | |
<head> | |
<title>4_howToPutSomeVerticalTextLikeProposalFontToCanvas.html</title> | |
<style> | |
canvas#vwrMain{ | |
border:1px solid black; | |
} | |
div#main{ | |
margin:5px; | |
} | |
</style> | |
<script> | |
// お名前付けるときの約束ごと: | |
// * newできるものは大英字ではじめるよね。 | |
// * 複数の単語で構成される名前の場合はcamelCaseでつなぐよね。 | |
// * 外からアクセスして欲しくないメンバは_で始めるよね。 | |
// * ローカル変数を明示したいときは_で始めるよね。 | |
// * 英単語を略記するのはローカル変数だけだよね。 | |
// * したがって略記してある変数はあえて_で始めなくてもいいよね。 | |
// * 引数をとるメソッドは他動詞だよね。 | |
// * isかhasで始まるメソッドは、明示的にtrue or falseで値を返すよね。 | |
function nameSpace(glb,spc){ | |
var ns = spc.split('.'); | |
var spcs = glb; | |
for(var i=0;i<ns.length;i++){ | |
spcs = spcs[ns[i]] = new Object(); | |
} | |
return spcs; | |
} | |
(function(_global,_$){ | |
// フォントメジャーは、実測した文字の幅と長さを取得します。 | |
_$.FontMeasure = function (){ | |
this._unitMeasure = _global.document.createElement('div'); | |
this._unitMeasure.style.position = 'absolute'; | |
this._unitMeasure.style.top = '0'; | |
this._unitMeasure.style.left = '0'; | |
this._unitMeasure.style.overflow = 'hidden'; | |
_global.document.body.appendChild(this._unitMeasure); | |
this._canvas = _global.document.createElement('canvas'); | |
this._canvas.height = 1200; | |
this._canvas.width = 1200; | |
this._sightScale = 5; | |
this._sizeDictionary = {}; | |
this.measure = function(_font,chr){ | |
// memoize | |
if(this._sizeDictionary[_font] && this._sizeDictionary[_font][chr]){ | |
return this._sizeDictionary[_font][chr]; | |
} | |
var cxt = this._canvas.getContext('2d'); | |
var fsz = 1; | |
var uni = '1px'; | |
var rct = null; | |
var _fontSettingSize = 1; | |
var _writedImage = null; | |
var _fontMeasuredSize = 1 | |
if(_font.match(/([0-9]+(\.[0-9]+)?)(px|pt|em)/)){ | |
fsz = RegExp.$1; | |
cxt.font = | |
this._unitMeasure.style.font = _font; | |
this._unitMeasure.style.width = | |
this._unitMeasure.style.height = '1'+RegExp.$3; | |
rct = this._unitMeasure.getBoundingClientRect(); | |
uni = (rct.right - rct.left); | |
_fontSettingSize = fsz * uni; | |
cxt.fillStyle = "#000000"; | |
cxt.fillRect(0,0,this._canvas.width,this._canvas.height); | |
cxt.textBaseline = 'top'; | |
cxt.fillStyle = cxt.strokeStyle = '#ff0000'; | |
cxt.fillText(chr, 0 , 0 ); | |
_writedImage = cxt.getImageData(0,0,_fontSettingSize , _fontSettingSize); | |
_fontMeasuredSize = _measureImage(_writedImage); | |
// 調整 | |
_fontMeasuredSize.width += _fontSettingSize/20; | |
_fontMeasuredSize.height += _fontSettingSize/10; | |
_fontMeasuredSize.unit = _fontSettingSize; | |
if( !this._sizeDictionary[_font] ){ | |
this._sizeDictionary[_font] = {}; | |
} | |
this._sizeDictionary[_font][chr] = _fontMeasuredSize; | |
console.log(chr+":("+_fontMeasuredSize.width+","+_fontMeasuredSize.height+")"); | |
return this._sizeDictionary[_font][chr]; | |
} | |
return { | |
width:void(0), | |
height:void(0), | |
unit:void(0) | |
}; | |
}; | |
_measureImage = function(_writedImage){ | |
var w = _writedImage.width; | |
var x = 0; | |
var y = 0; | |
var minX = 0; | |
var maxX = 1; | |
var minY = 0; | |
var maxY = 1; | |
for(var i=0;i<_writedImage.data.length;i+=4){ | |
if( | |
_writedImage.data[i+0] > 128 // 閾値がいまいち不安 | |
){ | |
if(x<minX) minX = x; | |
if(x>maxX) maxX = x; | |
if(y<minY) minY = y; | |
if(y>maxY) maxY = y; | |
} | |
x++; | |
if(x>=w){ | |
x=0; | |
y++; | |
} | |
} | |
return { | |
width : maxX - minX + 1, | |
height: maxY - minY + 1 | |
}; | |
} | |
}; | |
// テキストキャンバスは、キャンバスのIDを指定して、そこに文字列を縦書きします。 | |
_$.TextCanvas = function(_canvasId){ | |
this._fontMeasure = new _$.FontMeasure(); | |
this._canvas = _global.document.getElementById(_canvasId); | |
this._fontSize = 20; | |
this._charPointMap = new Array(); | |
this._text = ''; | |
this.putCharVertically = function(val,fsize){ | |
if(fsize) this._fontSize = fsize; | |
var cxt = this._canvas.getContext('2d'); | |
var hp = 0; | |
var hps = 0; | |
var vp = 0; | |
var vps = 0; | |
var chr = ''; | |
var stx = 0; | |
var _font = this._fontSize+'px Arial'; | |
var msr = null | |
this._text = val; | |
cxt.clearRect(0,0,this._canvas.width,this._canvas.height); | |
cxt.font = _font; | |
this._charPointMap = new Array(); | |
for(var i=0;i<val.length;i++){ | |
chr = val.charAt(i); | |
msr = this._fontMeasure.measure(_font,chr); | |
un = msr.unit; | |
if(chr.match(/[、。]/)){ | |
hp = -un/10; | |
vps = vps - un/2; | |
}else{ | |
hp = msr.width; | |
vp = msr.height; | |
} | |
stx = this._canvas.width - un*2 - hps; | |
sty = un + vps; | |
if( | |
( this._selectArea.st <= i && i <=this._selectArea.ed ) | |
|| | |
( this._selectArea.ed <= i && i <=this._selectArea.st ) | |
) | |
{ | |
cxt.strokeStyle = 'blue'; | |
cxt.fillStyle = 'blue'; | |
}else{ | |
cxt.strokeStyle = 'black'; | |
cxt.fillStyle = 'black'; | |
} | |
cxt.textBaseLine = 'top'; | |
cxt.fillText(chr, stx + un - hp/2, sty ); | |
this._charPointMap[this._charPointMap.length]=( | |
function(stx,sty,s,c){ | |
return function(x,y){ | |
return (stx+s/2 <= x && x <= stx+s*3/2 && sty-s <= y && y <= sty)?c:-1; | |
}; | |
})(stx,sty,un,i); | |
vps = vps + vp; | |
if(vps > this._canvas.height - un*2){ | |
hps += un; | |
vps = 0; | |
} | |
} | |
} | |
this._selectArea={st:-1,ed:-1}; | |
this._canvas.onmouseup = ( | |
function(prn){ | |
return function(e1){ | |
var st,ed; | |
prn._canvas.onmousemove = function(e2){}; | |
if(prn._selectArea.st >= 0){ | |
if(prn._selectArea.st < prn._selectArea.ed){ | |
st = prn._selectArea.st; | |
ed = prn._selectArea.ed+1; | |
}else{ | |
st = prn._selectArea.ed; | |
ed = prn._selectArea.st+1; | |
} | |
console.log(prn._text.substring(st,ed)); | |
} | |
prn._selectArea={st:-1,ed:-1}; | |
prn.putCharVertically(prn._text); | |
} | |
})(this); | |
this._selectText = function(num){ | |
if(num < 0) return; | |
if(this._selectArea.st < 0) | |
this._selectArea.st = num; | |
this._selectArea.ed = num; | |
} | |
this._canvas.onmousedown =( | |
function(prn){ | |
return function(e1){ | |
prn._selectText(_getCharPointFromMousePosition(e1,prn)); | |
prn._canvas.onmousemove = function(e2){ | |
prn.putCharVertically(prn._text); | |
prn._selectText(_getCharPointFromMousePosition(e2,prn)); | |
} | |
} | |
} | |
)(this); | |
_getCharPointFromMousePosition = function(e,prn){ | |
var rect = e.target.getBoundingClientRect(); | |
var x = e.clientX - rect.left; | |
var y = e.clientY - rect.top; | |
var _hits = prn._charPointMap; | |
var _hit = -1; | |
for(var i=0;i<_hits.length;i++){ | |
_hit = _hits[i](x,y); | |
if(_hit>=0){ | |
return _hit; | |
} | |
} | |
return -1; | |
}; | |
} | |
})( | |
this, | |
nameSpace(this,'aya.eiya.test') | |
); | |
</script> | |
</head> | |
<body onload="cvs = new aya.eiya.test.TextCanvas('vwrMain');cvs.putCharVertically(document.getElementById('inMain').value);"> | |
<h1>Canvasに縦書きで文字をプロポーサル風に表示する。</h1> | |
<p>HTML5のCanvasの練習です。Canvasに縦書きの文字を、文字の高さを確認しながら表示します。</p> | |
<p>割と面倒でした。</p> | |
<div id="main"> | |
<canvas id="vwrMain" width="300" height="300"></canvas> | |
</div> | |
<form> | |
<input type="text" id="inMain" onkeyup="cvs.putCharVertically(this.value);" | |
value="HTML5のCanvasの練習です。Canvasに縦書きの文字を、文字の高さを確認しながら表示します。" /> | |
</form> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html /> | |
<html> | |
<head> | |
<title>5_howToPutSomeSpecialCharactorsForVerticalStyle.html</title> | |
<style> | |
canvas#vwrMain{ | |
border:1px solid black; | |
} | |
div#main{ | |
margin:5px; | |
} | |
</style> | |
<script> | |
// お名前付けるときの約束ごと: | |
// * newできるものは大英字ではじめるよね。 | |
// * 複数の単語で構成される名前の場合はcamelCaseでつなぐよね。 | |
// * 外からアクセスして欲しくないメンバは_で始めるよね。 | |
// * ローカル変数を明示したいときは_で始めるよね。 | |
// * 英単語を略記するのはローカル変数だけだよね。 | |
// * したがって略記してある変数はあえて_で始めなくてもいいよね。 | |
// * 引数をとるメソッドは他動詞だよね。 | |
// * isかhasで始まるメソッドは、明示的にtrue or falseで値を返すよね。 | |
function nameSpace(glb,spc){ | |
var ns = spc.split('.'); | |
var spcs = glb; | |
for(var i=0;i<ns.length;i++){ | |
spcs = spcs[ns[i]] = new Object(); | |
} | |
return spcs; | |
} | |
(function(_global,_$){ | |
// フォントメジャーは、実測した文字の幅と長さを取得します。 | |
_$.FontMeasure = function (){ | |
this._unitMeasure = _global.document.createElement('div'); | |
this._unitMeasure.style.position = 'absolute'; | |
this._unitMeasure.style.top = '0'; | |
this._unitMeasure.style.left = '0'; | |
this._unitMeasure.style.overflow = 'hidden'; | |
_global.document.body.appendChild(this._unitMeasure); | |
this._canvas = _global.document.createElement('canvas'); | |
this._canvas.height = 1200; | |
this._canvas.width = 1200; | |
this._sightScale = 3; | |
this._sizeDictionary = {}; | |
this.measure = function(_font,chr){ | |
// memoize | |
if(this._sizeDictionary[_font] && this._sizeDictionary[_font][chr]){ | |
return this._sizeDictionary[_font][chr]; | |
} | |
var cxt = this._canvas.getContext('2d'); | |
var fsz = 1; | |
var uni = '1px'; | |
var rct = null; | |
var _fontSettingSize = 1; | |
var _writedImage = null; | |
var _fontMeasuredSize = 1 | |
if(_font.match(/([0-9]+(\.[0-9]+)?)(px|pt|em)/)){ | |
fsz = RegExp.$1; | |
cxt.font = | |
this._unitMeasure.style.font = _font; | |
this._unitMeasure.style.width = | |
this._unitMeasure.style.height = '1'+RegExp.$3; | |
rct = this._unitMeasure.getBoundingClientRect(); | |
uni = (rct.right - rct.left); | |
_fontSettingSize = fsz * uni; | |
cxt.fillStyle = "#000000"; | |
cxt.fillRect(0,0,this._canvas.width,this._canvas.height); | |
cxt.textBaseline = 'top'; | |
cxt.fillStyle = cxt.strokeStyle = '#ff0000'; | |
cxt.fillText(chr, _fontSettingSize , _fontSettingSize ); | |
_writedImage = cxt.getImageData( 0 , 0 ,_fontSettingSize * this._sightScale , _fontSettingSize * this._sightScale); | |
_fontMeasuredSize = _measureImage(_writedImage); | |
_fontMeasuredSize.unit = _fontSettingSize; | |
if(_fontMeasuredSize.startX > 0)_fontMeasuredSize.startX = _fontMeasuredSize.startX -_fontSettingSize; | |
if(_fontMeasuredSize.startY > 0)_fontMeasuredSize.startY = _fontMeasuredSize.startY -_fontSettingSize; | |
console.log( chr + ":" + _fontMeasuredSize.startX + "," +_fontMeasuredSize.startY); | |
if( !this._sizeDictionary[_font] ){ | |
this._sizeDictionary[_font] = {}; | |
} | |
this._sizeDictionary[_font][chr] = { | |
width :_fontMeasuredSize.width , | |
height:_fontMeasuredSize.height, | |
startX:_fontMeasuredSize.startX, | |
startY:_fontMeasuredSize.startY, | |
unit :_fontMeasuredSize.unit | |
}; | |
return this._sizeDictionary[_font][chr]; | |
} | |
return { | |
width :void(0), | |
height:void(0), | |
startX:void(0), | |
startY:void(0), | |
unit :void(0) | |
}; | |
}; | |
_measureImage = function(_writedImage){ | |
var w = _writedImage.width; | |
var h = _writedImage.height; | |
var x = 0; | |
var y = 0; | |
var minX = w; | |
var maxX = 1; | |
var minY = h; | |
var maxY = 1; | |
var i=0; | |
var j=0; | |
for(i=0;i<_writedImage.data.length;i+=4){ | |
if( | |
_writedImage.data[i+0] > 0 | |
){ | |
if(x<minX){ minX = x; } | |
if(x>maxX){ maxX = x; } | |
if(y<minY){ minY = y; } | |
if(y>maxY){ maxY = y; } | |
} | |
x++; | |
if(x>=w){ | |
x=0; | |
y++; | |
} | |
} | |
return { | |
width : (maxX >= minX)? maxX - minX : w, | |
height: (maxY >= minY)? maxY - minY : 1, | |
startX: (maxX >= minX)? minX : -1, | |
startY: (maxY >= minY)? minY : -1 | |
}; | |
} | |
}; | |
// テキストキャンバスは、キャンバスのIDを指定して、そこに文字列を縦書きします。 | |
_$.TextCanvas = function(_canvasId,_font){ | |
_initFont = function (_font){ | |
if(!_font) return "12pt Arial"; | |
if(!_font.match(/([0-9]+(\.[0-9]+)?)(px|pt|em)/)){ | |
return "12pt "+_font; | |
}else{ | |
return _font; | |
} | |
}; | |
_getCharPointFromMousePosition = function(e,prn){ | |
var rect = e.target.getBoundingClientRect(); | |
var x = e.clientX - rect.left; | |
var y = e.clientY - rect.top; | |
var _hits = prn._charPointMap; | |
var _hit = -1; | |
for(var i=0;i<_hits.length;i++){ | |
_hit = _hits[i](x,y); | |
if(_hit>=0){ | |
return _hit; | |
} | |
} | |
return -1; | |
}; | |
this._fontMeasure = new _$.FontMeasure(); | |
this._canvas = _global.document.getElementById(_canvasId); | |
this._font = _initFont(_font); | |
this._charPointMap = new Array(); | |
this._text = ''; | |
this.putCharVertically = function(val,_font){ | |
if(_font) this._font = _initFont(_font); | |
var cxt = this._canvas.getContext('2d'); | |
var hp = 0; | |
var hps = 0; | |
var vp = 0; | |
var vps = 0; | |
var chr = ''; | |
var stx = 0; | |
var premsr = null; | |
var msr = null; | |
var tmp = 0; | |
this._text = val; | |
cxt.clearRect(0,0,this._canvas.width,this._canvas.height); | |
cxt.font = this._font; | |
this._charPointMap = new Array(); | |
for(var i=0;i<val.length;i++){ | |
chr = val.charAt(i); | |
premsr = msr; | |
msr = this._fontMeasure.measure(this._font,chr); | |
un = msr.unit; | |
// small Charactors | |
if(chr.match(/[、。.,]/)){ | |
hp = msr.width - un - msr.startX; | |
vp = (premsr)?msr.height + premsr.height/2 : msr.height; | |
vps = (premsr)?vps - premsr.height/2 : vps; | |
}else{ | |
hp = msr.width + msr.startX; | |
vp = msr.height + msr.startY; | |
} | |
if( | |
( this._selectArea.st <= i && i <=this._selectArea.ed ) | |
|| | |
( this._selectArea.ed <= i && i <=this._selectArea.st ) | |
) | |
{ | |
cxt.strokeStyle = 'blue'; | |
cxt.fillStyle = 'blue'; | |
}else{ | |
cxt.strokeStyle = 'black'; | |
cxt.fillStyle = 'black'; | |
} | |
cxt.textBaseLine = 'top'; | |
// 90度回転表示する必要がある文字種 | |
if("{}()[]「」『』()【】[]{}…─━ー==~||".indexOf(chr) > -1){ | |
stx = this._canvas.width - un*2 - hps; | |
sty = un/4 + vps - msr.startX; | |
cxt.rotate(Math.PI / 2); | |
cxt.fillText(chr, sty , - (stx + un - hp/2)); | |
cxt.rotate(-Math.PI / 2); | |
hp = msr.height; | |
vp = msr.width; | |
}else{ | |
stx = this._canvas.width - un*2 - hps; | |
sty = un + vps; | |
cxt.fillText(chr, stx + un - hp/2, sty ); | |
} | |
this._charPointMap[this._charPointMap.length]=( | |
function(stx,sty,s,c){ | |
return function(x,y){ | |
return (stx+s/2 <= x && x <= stx+s*3/2 && sty-s <= y && y <= sty)?c:-1; | |
}; | |
})(stx,sty,un,i); | |
vps = vps + vp; | |
if(chr.charCodeAt(0) == 10 || vps > this._canvas.height - un*2){ | |
hps += un*1.5; | |
vps = 0; | |
} | |
} | |
} | |
this._selectArea={st:-1,ed:-1}; | |
this._canvas.onmouseup = ( | |
function(prn){ | |
return function(e1){ | |
var st,ed; | |
prn._canvas.onmousemove = function(e2){}; | |
if(prn._selectArea.st >= 0){ | |
if(prn._selectArea.st < prn._selectArea.ed){ | |
st = prn._selectArea.st; | |
ed = prn._selectArea.ed+1; | |
}else{ | |
st = prn._selectArea.ed; | |
ed = prn._selectArea.st+1; | |
} | |
console.log(prn._text.substring(st,ed)); | |
} | |
prn._selectArea={st:-1,ed:-1}; | |
prn.putCharVertically(prn._text); | |
} | |
})(this); | |
this._selectText = function(num){ | |
if(num < 0) return; | |
if(this._selectArea.st < 0) | |
this._selectArea.st = num; | |
this._selectArea.ed = num; | |
} | |
this._canvas.onmousedown =( | |
function(prn){ | |
return function(e1){ | |
prn._selectText(_getCharPointFromMousePosition(e1,prn)); | |
prn._canvas.onmousemove = function(e2){ | |
prn.putCharVertically(prn._text); | |
prn._selectText(_getCharPointFromMousePosition(e2,prn)); | |
} | |
} | |
} | |
)(this); | |
} | |
})( | |
this, | |
nameSpace(this,'aya.eiya.test') | |
); | |
</script> | |
</head> | |
<body onload="cvs = new aya.eiya.test.TextCanvas('vwrMain');cvs.putCharVertically(document.getElementById('inMain').value);"> | |
<h1>Canvasに縦書きで特殊な文字も自然に表示する。</h1> | |
<p>HTML5のCanvasの練習です。Canvasに縦書きで括弧などの文字を自然に表示します。</p> | |
<p>せっかくなので改行にも対応しました。</p> | |
<div id="main"> | |
<canvas id="vwrMain" width="300" height="300"></canvas> | |
</div> | |
<form> | |
Font : <input type="text" id="font" value="12pt Arial" /><br /> | |
Text <br /><textarea id="inMain" | |
style="width:280px;height:120px" | |
onkeyup="cvs.putCharVertically(this.value,document.getElementById('font').value);"> | |
HTML5のCanvasの練習です。Canvasに縦書きで括弧などの文字を90度回転させて自然な形で表示します。 | |
「このような(括弧)が(自然な)形で{表示されていると}」 | |
{成功と『言え』ます…} | |
</textarea> | |
</form> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
お疲れ様です。
@aya-eiya、おはようございます。
縦書きをキャンバスにレンダリングするデモを公開していただき、ありがとうございます。🙇♂️
彼らはとても役に立ちます。😊
私は縦書きをfabric.jsフレームワークに統合しています。🙂
Webアプリに縦書きを実装してみましたか。
できれば、縦書きについてのより高度な例を共有していただけませんか。
よろしくお願いいたします。🙇♂️