繁体   English   中英

如何在圆形html画布中居中放置字母?

[英]How can I center a letter in circle html canvas?

到目前为止,要进行居中,我正在使用以下两行代码:

ctx.textAlign="center"; 
ctx.textBaseline = "middle";

几乎可以完成工作,但是某些字符(例如“ g”和“ y”)并未完全居中。 如何确保所有这些功能均受支持? 是一个JSbin,表明大多数字符(例如“ g”)都在中心线下方。

期望: 在此处输入图片说明

现实: 在此处输入图片说明

为了使我的“期望”起作用,我从字母的y值中减去了15px,但这使“ a”这样的小字母弄乱了,并使它们超出了顶部的范围。

测量文字。

一种方法是渲染角色,然后扫描像素以找到范围,顶部,底部,左侧和右侧,以找到角色的真实中心。

这是一个非常昂贵的过程,因此您需要将以前的测量结果存储在地图中,并以相同的字符和字体返回这些结果。

下面的示例创建对象charSizer 设置字体charSizer.font = "28px A font"即可获取有关任何字符的信息。 charSizer.measure(char)返回包含有关字符尺寸信息的对象。

您可以测量生产中的字符并将信息提供给页面,以减少客户端的处理,但是您将需要针对每个浏览器,因为它们均以不同的方式呈现文本。

该示例包含说明。 左画布使用ctx.textAlign = "center"ctx.textBaseline = "middle" char渲染到正常中心。 还包括彩色拼合线,以显示范围,中心,边界中心和加权中心。 中间的画布使用边界中心画圆,而右画布使用加权中心。

这仅是示例,未经测试且未达到生产质量。

 const charSizer = (() => { const known = new Map(); var w,h,wc,hc; const workCan = document.createElement("canvas"); const ctx = workCan.getContext("2d"); var currentFont; var fontHeight = 0; var fontId = ""; function resizeCanvas(){ wc = (w = workCan.width = fontHeight * 2.5 | 0) / 2; hc = (h = workCan.height = fontHeight * 2.5 | 0) / 2; ctx.font = currentFont; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillStyle = "black"; } function measure(char){ const info = { char, width : ctx.measureText(char).width, top : null, left : w, right : 0, bottom : 0, weightCenter : { x : 0, y : 0 }, center : { x : 0, y : 0 }, offset : { x : 0, y : 0 }, wOffset : { x : 0, y : 0 }, area : 0, width : 0, height : 0, } ctx.clearRect(0,0,w,h); ctx.fillText(char,wc,hc); const pixels8 = ctx.getImageData(0,0,w,h).data; const pixels = new Uint32Array(pixels8.buffer); var x,y,i; i = 0; for(y = 0; y < h; y ++){ for(x = 0; x < w; x ++){ const pix = pixels[i++]; if(pix){ const alpha = pixels8[(i<<2)+3]; info.bottom = y; info.right = Math.max(info.right, x); info.left = Math.min(info.left, x); info.top = info.top === null ? y : info.top; info.area += alpha; info.weightCenter.x += (x - wc) * (alpha/255); info.weightCenter.y += (y - hc) * (alpha/255); } } } if(info.area === 0){ return {empty : true}; } info.area /= 255; info.weightCenter.x /= info.area; info.weightCenter.y /= info.area; info.height = info.bottom - info.top + 1; info.width = info.right - info.left + 1; info.center.x = info.left + info.width / 2; info.center.y = info.top + info.height / 2; info.offset.x = wc - info.center.x; info.offset.y = hc - info.center.y; info.wOffset.x = -info.weightCenter.x; info.wOffset.y = -info.weightCenter.y; info.top -= hc; info.bottom -= hc; info.left -= wc; info.right -= wc; info.center.x -= wc; info.center.y -= hc; return info; } const API = { set font(font){ currentFont = font; fontHeight = Number(font.split("px")[0]); resizeCanvas(); fontId = font; }, measure(char){ var info = known.get(char + fontId); if(info) { return {...info} } // copy so it is save from change info = measure(char); known.set(char + fontId,info); return info; } } return API; })() //============================================================================== //============================================================================== // Demo code from here down not part of answer code. const size = 160; const sizeh = 80; const fontSize = 120; function line(x,y,w,h){ ctx.fillRect(x,y,w,h); } function hLine(y){ line(0,y,size,1) } function vLine(x){ line(x,0,1,size) } function circle(ctx,col = "red",x= sizeh,y = sizeh,r = sizeh*0.8,lineWidth = 2) { ctx.lineWidth = lineWidth; ctx.strokeStyle = col; ctx.beginPath(); ctx.arc(x,y,r,0,Math.PI * 2); ctx.stroke(); } const ctx = canvas.getContext("2d"); const ctx1 = canvas1.getContext("2d"); const ctx2 = canvas2.getContext("2d"); canvas.width = size; canvas.height = size; canvas1.width = size; canvas1.height = size; canvas2.width = size; canvas2.height = size; canvas.addEventListener("click",nextChar); canvas1.addEventListener("click",nextFont); ctx.font = "20px Arial"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText("Click this canvas", sizeh,sizeh-30); ctx.fillText("cycle", sizeh,sizeh); ctx.fillText("characters", sizeh,sizeh + 30); ctx1.font = "20px Arial"; ctx1.textAlign = "center"; ctx1.textBaseline = "middle"; ctx1.fillText("Click this canvas", sizeh,sizeh - 30); ctx1.fillText("cycle", sizeh,sizeh); ctx1.fillText("fonts", sizeh,sizeh + 30); charSizer.font = "128px Arial"; ctx1.textAlign = "center"; ctx1.textBaseline = "middle"; ctx2.textAlign = "center"; ctx2.textBaseline = "middle"; const chars = "\\"ABCDQWZ{@pqjgw|/*"; const fonts = [ fontSize+"px Arial", fontSize+"px Arial Black", fontSize+"px Georgia", fontSize+"px Impact, Brush Script MT", fontSize+"px Rockwell Extra Bold", fontSize+"px Franklin Gothic Medium", fontSize+"px Brush Script MT", fontSize+"px Comic Sans MS", fontSize+"px Impact", fontSize+"px Lucida Sans Unicode", fontSize+"px Tahoma", fontSize+"px Trebuchet MS", fontSize+"px Verdana", fontSize+"px Courier New", fontSize+"px Lucida Console", fontSize+"px Georgia", fontSize+"px Times New Roman", fontSize+"px Webdings", fontSize+"px Symbol",]; var currentChar = 0; var currentFont = 0; var firstClick = true; function nextChar(){ if(firstClick){ setCurrentFont(); firstClick = false; } ctx.clearRect(0,0,size,size); ctx1.clearRect(0,0,size,size); ctx2.clearRect(0,0,size,size); var c = chars[(currentChar++) % chars.length]; var info = charSizer.measure(c); if(!info.empty){ ctx.fillStyle = "red"; hLine(sizeh + info.top); hLine(sizeh + info.bottom); vLine(sizeh + info.left); vLine(sizeh + info.right); ctx.fillStyle = "black"; hLine(sizeh); vLine(sizeh); ctx.fillStyle = "red"; hLine(sizeh + info.center.y); vLine(sizeh + info.center.x); ctx.fillStyle = "blue"; hLine(sizeh + info.weightCenter.y); vLine(sizeh + info.weightCenter.x); ctx.fillStyle = "black"; circle(ctx,"black"); ctx.fillText(c,sizeh,sizeh); ctx1.fillStyle = "black"; circle(ctx1); ctx1.fillText(c,sizeh + info.offset.x,sizeh+ info.offset.y); ctx2.fillStyle = "black"; circle(ctx2,"blue"); ctx2.fillText(c,sizeh + info.wOffset.x, sizeh + info.wOffset.y); } } function setCurrentFont(){ fontUsed.textContent = fonts[currentFont % fonts.length]; charSizer.font = fonts[currentFont % fonts.length]; ctx.font = fonts[currentFont % fonts.length]; ctx2.font = fonts[currentFont % fonts.length]; ctx1.font = fonts[(currentFont ++) % fonts.length]; } function nextFont(){ setCurrentFont(); currentChar = 0; nextChar(); } 
 canvas { border : 2px solid black; } .red {color :red;} .blue {color :blue;} 
 <canvas id="canvas"></canvas><canvas id="canvas1"></canvas><canvas id="canvas2"></canvas><br> Font <span id="fontUsed">not set</span> [center,middle] <span class=red>[Spacial center]</span> <span class=blue> [Weighted center]</span><br> Click left canvas cycles char, click center to cycle font. Not not all browsers support all fonts 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM