javascript - 如何在 HTML5 Canvas 中随文本一起绘制和旋转图像

标签 javascript html canvas

我在 Canvas 上绘制和旋转图像时遇到问题。基本上,我的方法是创建命运之轮,允许根据数组形式的奖品进行定制。该数组中的数据根据​​索引的数量组成了轮子内的段。

数据非常简单。它只是一个像这样的简单 JSON 对象

var prizes = [
{product:"Axe FX", img: "https://mdn.mozillademos.org/files/5395/backdrop.png"},
{product:"Musicman JPX", img: "https://mdn.mozillademos.org/files/5395/backdrop.png"},
{product:"Ibanez JEM777V", img: "https://mdn.mozillademos.org/files/5395/backdrop.png"}
];

此数据用于创建轮内的分段。所以我想放置当前对我来说很有吸引力的文本。

在绘制轮子时,我分为两个主要功能。一个用于绘制轮子,另一个用于绘制轮子内的分段。

var drawPartial = function(key, lastAngle, angle) {
var value = prizes[key].product;

ctx.save();
ctx.beginPath();
ctx.lineWidth = 6;
ctx.fillStyle = segColors[key];
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, size, lastAngle, angle);
ctx.lineTo(centerX, centerY);
ctx.closePath();
ctx.stroke();
ctx.fill();

ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate((lastAngle+angle) / 2);
ctx.fillStyle = "#000";
ctx.fillText(value.substr(0,20), size / 2 + 20, 0);
ctx.restore();

ctx.restore();
}

var draw = function() {
var len = prizes.length;
var currentAngle = outCurrentAngle;
var lastAngle = currentAngle;

ctx.strokeStyle = '#000000';
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.font = "1.4em Arial";

for(var i = 1; i <= len; i++) {
    var angle = (Math.PI*2) * (i/len) + currentAngle;
    drawPartial(i-1, lastAngle, angle);
    lastAngle = angle;
}

ctx.beginPath();
ctx.lineWidth = 2;
ctx.fillStyle = "#fff";
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, size/7, 0, Math.PI*2);
ctx.closePath();
// ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.lineWidth = 10;
ctx.arc(centerX, centerY, size, 0, Math.PI*2);
ctx.closePath();
// ctx.stroke();
}

通过上面的代码,我只需简单地调用draw()函数,轮子和所有段就会相应地创建。但是,我想在每个部分绘制图像,但我不知道如何使其工作。这是对drawPartial()的修改,用于渲染图像和文本

var drawPartial = function(key, lastAngle, angle) {
var value = prizes[key].product;

var img = new Image();
img.src = prizes[key].img;
img.onload = function() { 

    ctx.save();
    ctx.drawImage(img,centerX,centerY);

    ctx.save();
    ctx.translate(centerX,centerY);
    ctx.rotate((lastAngle+angle) / 2);
    ctx.drawImage(img,centerX,centerY);

    ctx.restore();
    ctx.restore();


}

ctx.save();
ctx.beginPath();
ctx.lineWidth = 6;
ctx.fillStyle = segColors[key];
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, size, lastAngle, angle);
ctx.lineTo(centerX, centerY);
ctx.closePath();
ctx.stroke();
ctx.fill();

ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate((lastAngle+angle) / 2);
ctx.fillStyle = "#000";
ctx.fillText(value.substr(0,20), size / 2 + 20, 0);
ctx.restore();

ctx.restore();
}

您可以看到我根据奖品对象添加了图像及其 src,该对象应该在主 draw() 函数调用的每次迭代中调用,但它永远不会在任何片段中渲染任何图像。

我想要的是。在drawPartial()的每次迭代中,我希望图像与文本一起放置在片段中,并根据 Angular 旋转。

请帮忙...

最佳答案

问题

在您的 img.onload 函数中,您正在“双重翻译”您的 centerX 和 centerY。

ctx.translate(centerX,centerY) 会将 Canvas 的 [0,0] 原点移动到 [centerX,centerY]。

因此,当您ctx.drawImage(img,centerX,centerY)绘制图像时,您实际上是在双重移动。

因此,您的图像实际上是在 [ centerX*2, centerY*2 ] 处绘制的。

附加想法:预加载图像

最好预加载所有图像。这样,如果图像加载失败,您可以在开始绘制轮子之前采取修复操作。

以下是如何预加载所有图像,以便在您需要将它们绘制到轮子上时可用:

// your incoming JSON 
var prizesJSON='[{"product":"Axe FX","img":"https://mdn.mozillademos.org/files/5395/backdrop.png"},{"product":"Musicman JPX","img":"https://mdn.mozillademos.org/files/5395/backdrop.png"},{"product":"Ibanez JEM777V","img":"https://mdn.mozillademos.org/files/5395/backdrop.png"}]';

// the JSON converted to a JS array of objects
var prizes=JSON.parse(prizesJSON);

// preload all images
var imageURLs=[];  
var imgs=[];
var imagesOK=0;
// add prize images into the image preloader
for(var i=0;i<prizes.length;i++){
  imageURLs.push(prizes[i].img);
}
startLoadingAllImages(imagesAreNowLoaded);
//
function startLoadingAllImages(callback){
  for (var i=0; i<imageURLs.length; i++) {
    var img = new Image();
    imgs.push(img);
    img.onload = function(){ 
      imagesOK++; 
      if (imagesOK>=imageURLs.length ) {
        callback();
      }
    };
    img.onerror=function(){alert("image load failed");} 
    img.src = imageURLs[i];
  }      
}
// 
function imagesAreNowLoaded(){
  // add the img objects to your prizes array objects
  for(var i=0;i<prizes.length;i++){
    prizes[i].imageObject=imgs[i];
    // just testing (add the img to the DOM)
    document.body.appendChild(imgs[i]);
  }
  // All images are fully loaded
  // So draw your wheel now!
}
body{ background-color: ivory; }
<h4>Testing: (1) Preload all images, (2) Add imgs to DOM</h4>

我有这个...

我看到您已经有了绘制轮子的代码,但我的代码存档中有此代码,因此我在这里提供它,以防万一它对您有用。

这里是如何绘制“命运之轮”的示例,每个叶片都包含奖品图像和文本。使用的技术包括:

  • context.translate 将旋转点设置为滚轮中心。
  • context.rotate 将每个 Blade 旋转到所需的 Angular 。
  • context.textAligncontext.textBaseline 绘制居中文本。
  • context.globalAlpha 淡化每个 Blade 的颜色,使黑色文本具有良好的对比度。

enter image description here

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

var PI=Math.PI;
var PI2=PI*2;
var bladeCount=10;
var sweep=PI2/bladeCount;
var cx=cw/2;
var cy=ch/2;
var radius=130;

var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house32x32transparent.png";
function start(){
    for(var i=0;i<bladeCount;i++){
        drawBlade(img,'House'+i,cx,cy,radius,sweep*i,sweep);
    }    
}

function drawBlade(img,text,cx,cy,radius,angle,arcsweep){
    // save the context state 
    ctx.save();
    // rotate the canvas to this blade's angle
    ctx.translate(cx,cy);
    ctx.rotate(angle);
    // draw the blade wedge
    ctx.lineWidth=1.5;
    ctx.beginPath();
    ctx.moveTo(0,0);
    ctx.arc(0,0,radius,0,arcsweep);
    ctx.closePath();
    ctx.stroke();
    // fill the blade, but keep the color light
    // so the black text has good contrast
    ctx.fillStyle='white';
    ctx.fill();
    ctx.fillStyle=randomColor();
    ctx.globalAlpha=0.30;
    ctx.fill();
    ctx.globalAlpha=1.00;
    // draw the text
    ctx.rotate(PI/2+sweep/2);
    ctx.textAlign='center';
    ctx.textBaseline='middle';
    ctx.fillStyle='black';
    ctx.fillText(text,0,-radius+50);
    // draw the img 
    // (resize to 32x32 so be sure orig img is square)
    ctx.drawImage(img,-16,-radius+10,32,32);
    // restore the context to its original state
    ctx.restore();
}

function randomColor(){ 
    return('#'+Math.floor(Math.random()*16777215).toString(16));
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>

关于javascript - 如何在 HTML5 Canvas 中随文本一起绘制和旋转图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32173955/

相关文章:

c# - 需要帮助从 C# 中的 HTML 页面中提取标签

javascript - HTML5 Canvas 相机/视口(viewport) - 如何实际操作?

javascript - 为 Dart 二进制 websocket 从 ByteBuffer 读取/写入固定大小的 int 和字符串

javascript - 如何在 Vue.js 中指定绑定(bind)上下文,就像在 Knockout.js 和 WPF 中一样

javascript - 这是标签导航吗?如果是,如何导航?

javascript - 附加了 jQuery 的内联元素换行

javascript - Chart.js donut 段内的图片

javascript - 在不重绘的情况下向现有 Canvas 添加更多空间?

javascript - jQuery 追加/添加隐藏 div 到 jQuery 对话框

javascript - 通过字符串获取对象变量的问题