canvas js用图片填充弧线

时间:2019-01-10 21:24:26

标签: javascript html5 canvas design-patterns automatic-ref-counting

我正在尝试用图像填充圆(弧)。

这是我的代码:

draw() {
ctx.save();
let boulePat = new Image();
switch(this.couleur) {
  case "red":
    boulePat.src = "images/red.png";
    break;
  case "green":
    boulePat.src = "images/green.png";
    break;
  case "orange":
    boulePat.src = "images/orange.png";
    break;
  case "yellow":
    boulePat.src = "images/yellow.png";
    break; 
  case "purple":
    boulePat.src = "images/purple.png";
    break;
 }
  var pattern = ctx.createPattern(boulePat, "repeat");
  ctx.beginPath();
  ctx.arc(this.x, this.y, 15, 0, 2 * Math.PI);
  ctx.fillStyle = pattern;
  ctx.fill();
  ctx.restore();
}

有了这个,我有一个空的或黑色的圆圈...

能帮我吗? 非常感谢。

2 个答案:

答案 0 :(得分:0)

您必须等待图像加载,然后才能在createPattern中使用它,如下所示:

请参见this stack answer

请记住,图像将从相对于画布的0,0坐标开始。必要时,您需要将此因素考虑在内(使用ctx.transform(xOffset, yOffset))。

var canvas = document.getElementById("myCanvasNoTranslate");
var canvas2 = document.getElementById("myCanvasWithTranslate");

function drawCanvas(_canvas) {
  var context = _canvas.getContext("2d");
  draw(context);
}

function draw(ctx) {
  ctx.save();
  ctx.strokeSyle = "rgb(0, 0, 0)";
  ctx.lineWidth = 3;
  ctx.strokeRect(0, 0, 400, 200);
  
  let boulePat = new Image();
  boulePat.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/16777216colors.png/100px-16777216colors.png";
  boulePat.onload = function () {
    var pattern = ctx.createPattern(boulePat, "repeat");
    ctx.fillStyle = pattern;
    ctx.beginPath();
    ctx.arc(100, 100, 50, 0, 2 * Math.PI);
    // translate canvas to offset where the image coordinates are for .fill()
    if (ctx.canvas === canvas2) {
      ctx.translate(50, 50);  
    }
    ctx.fill();
    // restore ctx back to before the translate()
    ctx.restore();
  }
}

drawCanvas(canvas);
drawCanvas(canvas2);
With ctx.translate() for background fill<br/>
<canvas id="myCanvasWithTranslate" height="200px" width="400px"></canvas>
<br/><br/>
Without ctx.translate() for background fill<br/>
<canvas id="myCanvasNoTranslate" height="200px" width="400px"></canvas>

答案 1 :(得分:0)

下面的代码采用图像 URL、弧的半径和弧的角度/大小,并返回一个画布,该画布将该图像剪辑到给定的弧,并“包含”在弧内,使得图像填充圆弧而不改变图像的纵横比:

  async function getArcClippedCanvas(imageUrl, radius, arcSizeDeg) {   
    let arcSizeRad = (arcSizeDeg/360)*2*Math.PI;
    
    // derive required width and height of canvas from radius and arc size
    let width;
    if(arcSizeDeg >= 180) {
      width = radius*2;
    } else {
      width = radius*Math.sin(arcSizeRad/2)*2;
    }
    
    let height;
    if(arcSizeDeg <= 180) {
      height = radius;
    } else {
      height = radius + radius*Math.sin( (arcSizeRad-Math.PI)/2 );
    }
    
    let arcCenterX = width/2;
    let arcCenterY = radius; // remember, y axis starts from top of canvas
     
    let canvas = document.createElement("canvas");
    let ctx = canvas.getContext("2d");
    
    canvas.width = width;
    canvas.height = height;
    
    let img = new Image();
    await new Promise(resolve => {
      img.onload = resolve;
      img.src = imageUrl;
    });
    
    let centerAngle = -Math.PI/2;
    
    ctx.beginPath();
    ctx.moveTo(arcCenterX, arcCenterY); 
    ctx.arc(arcCenterX, arcCenterY, radius, centerAngle - (arcSizeDeg/2)*2*Math.PI/360, centerAngle + (arcSizeDeg/2)*2*Math.PI/360);
    ctx.clip();
    
    // we want to "cover" the canvas with the image without changing the image's aspect ratio
    drawImageToCanvasContained(ctx, img, 0, 0, canvas.width, canvas.height);
    
    return canvas;
  }


  function drawImageToCanvasContained(ctx, img, x, y, w, h, offsetX, offsetY) {
    // By Ken Fyrstenberg Nilsen: https://stackoverflow.com/a/21961894/11950764
    if(arguments.length === 2) {
      x = y = 0;
      w = ctx.canvas.width;
      h = ctx.canvas.height;
    }

    // default offset is center
    offsetX = typeof offsetX === "number" ? offsetX : 0.5;
    offsetY = typeof offsetY === "number" ? offsetY : 0.5;

    // keep bounds [0.0, 1.0]
    if(offsetX < 0) offsetX = 0;
    if(offsetY < 0) offsetY = 0;
    if(offsetX > 1) offsetX = 1;
    if(offsetY > 1) offsetY = 1;

    let iw = img.width;
    let ih = img.height;
    let r = Math.min(w / iw, h / ih);
    let nw = iw * r;   // new prop. width
    let nh = ih * r;   // new prop. height
    let cx, cy, cw, ch, ar = 1;

    // decide which gap to fill    
    if(nw < w) ar = w / nw;                             
    if(Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh;  // updated
    nw *= ar;
    nh *= ar;

    // calc source rectangle
    cw = iw / (nw / w);
    ch = ih / (nh / h);

    cx = (iw - cw) * offsetX;
    cy = (ih - ch) * offsetY;

    // make sure source rectangle is valid
    if(cx < 0) cx = 0;
    if(cy < 0) cy = 0;
    if(cw > iw) cw = iw;
    if(ch > ih) ch = ih;

    // fill image in dest. rectangle
    ctx.drawImage(img, cx, cy, cw, ch,  x, y, w, h);
  }