簡體   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