在画布上抚摸文本

Hel*_*eda 5 javascript canvas html5-canvas

我注意到一个有趣的效果混合进来setLineDash,并strokeText在画布

ctx = document.querySelector("canvas").getContext("2d")
ctx.font = "110px Arial";
i = speed = 3

function loop() {
  ctx.clearRect(0, 0, 600, 160)
  ctx.beginPath()
  ctx.setLineDash([i, 600]);
  ctx.strokeText("WORLD ?", 10, 100);
  i += speed
  if (i > 600 || i < 2)
    speed *= -1
}

setInterval(loop, 50)
Run Code Online (Sandbox Code Playgroud)
<canvas id="c" width=600 height=160></canvas>
Run Code Online (Sandbox Code Playgroud)

如您所见W,绘制所需的时间比O此代码段中的更长。
是否有任何属性可以检索字母最长行的像素数(长度)?

Jan*_*nkt 2

您可以在屏幕外绘制每个字符并“计算”像素的出现次数(非零值):

\n\n
function getAmount (char, { width, height, font, color }) {\n  // create temporary offscreen canvas\n  const canvas = document.createElement(\'canvas\')\n  canvas.width = width\n  canvas.height = height\n\n  // draw the character\n  const ctx = canvas.getContext("2d")\n  ctx.font = font\n  ctx.strokeText(char, 0, 90)\n\n  // get the pixels data\n  const imageData = ctx.getImageData(0, 0, width, height)\n  let sum = 0\n  imageData.data.forEach(point => {\n    if (point > 0) sum++\n  })\n  return sum\n}\n\nconst width = 90\nconst height = 90\nconst font = "90px Arial"\n\ngetAmount(\'W\', { font, width, height }) // 940\ngetAmount(\'O\', { font, width, height }) // 660\ngetAmount(\'R\', { font, width, height }) // 673\ngetAmount(\'L\', { font, width, height }) // 296\ngetAmount(\'D\', { font, width, height }) // 613\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以粗略地使用这些值来加权速度并单独绘制每个角色,但请记住,您必须另外管理放置等。此外,这仅检测任何非零值。如果您对笔划使用渐变,则必须检测渐变范围内的图像数据。

\n\n

编辑:

\n\n

由于找不到真相来源,我们可以使用另一个技巧:

\n\n

i求创建与全虚线字符具有相同像素数量的屏幕外图像的数量。

\n\n
/**\n * draws a stroked text by given params to a context\n **/\n\nfunction draw (char, ctx, minValue, maxValue) {\n  ctx.clearRect(0, 0, 600, 160)\n  ctx.beginPath()\n  if (minValue && maxValue) {\n    ctx.setLineDash([minValue, maxValue])\n  }\n  ctx.strokeText(char, 10, 100);\n}\n\n/**\n * Returns the amount of pixels for a given character\n */\nconst offscreenCanvas = document.createElement(\'canvas\')\nfunction getAmount (char, { value, max,  width, height, font }) {\n  // draw offscreen, then detect border pixels\n  offscreenCanvas.width = width\n  offscreenCanvas.height = height\n\n  // draw the character\n  const ctx = offscreenCanvas.getContext("2d")\n  ctx.font = font\n  draw(char, ctx, value, max)\n\n  // get the pixels data\n  const imageData = ctx.getImageData(0, 0, width, height)\n  let sum = 0\n  imageData.data.forEach(point => {\n    if (point > 0) sum++\n  })\n\n  return sum\n}\n\n/**\n * Returns the number of iterations required to complete a character\n **/\n\nfunction getIterations (char, { font, width, height }) {\n  // get amount when word is fully drawn\n  const fullAmount = getAmount(char, { value: undefined, max: undefined, width, height, font })\n\n  let iterations = 1\n  let amount = 0\n  do {\n    amount = getAmount(char, { value: iterations, max: 1000, width, height, font })\n    iterations++\n  } while ((amount - fullAmount < -3) && iterations < 2000);\n\n  return iterations\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

从这里我们可以确定参数i的值setLineDash

\n\n
const font = "110px Arial";\nconst width = 110\nconst height = 110\n\nconst check = char => {\n  const amount = getIterations(char, { font, width, height })\n  console.log(char, amount)\n}\n\n\ncheck(\'W\')  // 620\ncheck(\'O\')  // 243\ncheck(\'R\')  // 331\ncheck(\'L\')  // 248\ncheck(\'D\')  // 248\ncheck(\'\xe3\x81\xb5\') // 185\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用这些值,您可以创建一个相对speed参数,使您可以同时完成笔划。

\n\n

请注意,这种方法是超级贪婪的,并不是真正的性能优化,而是一种概念证明。

\n