【问题标题】:How to get width & height of drawn arc(s) in HTML5 Canvas?如何在 HTML5 Canvas 中获取绘制弧的宽度和高度?
【发布时间】:2015-08-05 07:28:02
【问题描述】:

Here我已经使用Konvajs库绘制了一些弧,但是在绘制对象后我无法获得它们的宽度和高度,我该怎么做? 快速阅读代码:

function drawSurface(idnumber, radius, x, y, startAngleParam, endAngleParam) {
var borderbold = 5;
var surface;
if (typeof startAngleParam !== 'undefined') {
    surface = new Konva.Shape({
        x: x,
        y: y,
        fill: '#ccc',
        stroke: "#ccc",
        strokeWidth: 8,
        id: idnumber,
        opacity: 1,
        drawFunc: function (context) {
            var startAngle = startAngleParam * Math.PI;
            var endAngle = (startAngleParam + 0.5 + endAngleParam) * Math.PI;
            var counterClockwise = false;
            context.beginPath();
            context.arc(0, 0, radius, startAngle, endAngle, counterClockwise);
            context.setAttr("lineWidth", borderbold);
            context.stroke();
            context.fillStrokeShape(this);
        }
    });
}
else {
    surface = new Konva.Circle({
        x: x,
        y: y,
        radius: radius,
        fill: '#ccc',
        strokeWidth: 3,
        id: idnumber,
        opacity: 1
    });
}
return surface;
}

请用代码示例支持您的回答。

【问题讨论】:

    标签: html canvas html5-canvas kineticjs konvajs


    【解决方案1】:

    这是从this answer 中采用并移植到 Javascript 的另一种方法:

    const PI = Math.PI;
    const HALF_PI = Math.PI / 2;
    const TWO_PI = Math.PI * 2;
    const DEG_TO_RAD = Math.PI / 180;
    const RAD_TO_DEG = 180 / Math.PI;
    
    const getQuadrant = (_angle) => {
        const angle = _angle % (TWO_PI);
    
        if (angle > 0.0 && angle < HALF_PI) return 0;
        if (angle >= HALF_PI && angle < PI) return 1;
        if (angle >= PI && angle < PI + HALF_PI) return 2;
        return 3;
    };
    
    // https://stackoverflow.com/a/35977476/461048
    const getArcBoundingBox = (ini, end, radius, margin = 0) => {
        const iniQuad = getQuadrant(ini);
        const endQuad = getQuadrant(end);
    
        const ix = Math.cos(ini) * radius;
        const iy = Math.sin(ini) * radius;
        const ex = Math.cos(end) * radius;
        const ey = Math.sin(end) * radius;
    
        const minX = Math.min(ix, ex);
        const minY = Math.min(iy, ey);
        const maxX = Math.max(ix, ex);
        const maxY = Math.max(iy, ey);
    
        const r = radius;
        const xMax = [[maxX, r, r, r], [maxX, maxX, r, r], [maxX, maxX, maxX, r], [maxX, maxX, maxX, maxX]];
        const yMax = [[maxY, maxY, maxY, maxY], [r, maxY, r, r], [r, maxY, maxY, r], [r, maxY, maxY, maxY]];
        const xMin = [[minX, -r, minX, minX], [minX, minX, minX, minX], [-r, -r, minX, -r], [-r, -r, minX, minX]];
        const yMin = [[minY, -r, -r, minY], [minY, minY, -r, minY], [minY, minY, minY, minY], [-r, -r, -r, minY]];
    
        const x1 = xMin[endQuad][iniQuad];
        const y1 = yMin[endQuad][iniQuad];
        const x2 = xMax[endQuad][iniQuad];
        const y2 = yMax[endQuad][iniQuad];
    
        const x = x1 - margin;
        const y = y1 - margin;
        const w = x2 - x1 + margin * 2;
        const h = y2 - y1 + margin * 2;
    
        return { x, y, w, h };
    };
    

    jsfiddle:https://jsfiddle.net/brunoimbrizi/y3to5s6n/45/

    【讨论】:

      【解决方案2】:

      找到弧的边界框,然后根据边界框计算宽度和高度。

      在几何上,仅有 5 个可能的边界框角是:

      • 圆弧中心点,
      • 圆弧上的点(如果有)在 0 度(0 弧度),
      • 圆弧上的点(如果有)90 度(PI/2 弧度),
      • 圆弧上的点(如果有)在 180 度(PI 弧度),
      • 圆弧上的点(如果有)270 度(PI*3/2 弧度),

      从这些可能的边界框点中,找到最小 X、最小 Y、最大 X 和最大 Y。[minX,minY] 将是边界框的左上角。 [maxX,maxY] 将是边界框的右下角。

      您的弧宽将为 maxX-minX,高度为 maxY-minY。

      这是示例代码和演示:

      var canvas=document.getElementById("canvas");
      var ctx=canvas.getContext("2d");
      var cw=canvas.width;
      var ch=canvas.height;
      
      
      var PI=Math.PI;
      var cx=150;
      var cy=150;
      var radius=75;
      var startAngle=-PI/4;
      var endAngle=PI/3;
      
      ctx.beginPath();
      ctx.moveTo(cx,cy);
      ctx.arc(cx,cy,radius,startAngle,endAngle);
      ctx.closePath();
      ctx.fillStyle='skyblue';
      ctx.fill();
      ctx.strokeStyle='lightgray';
      ctx.lineWidth=3;
      ctx.stroke();
      
      var bb=arcBounds(cx,cy,radius,startAngle,endAngle);
      ctx.strokeStyle='red';
      ctx.lineWidth=1;
      ctx.strokeRect(bb.x,bb.y,bb.width,bb.height);
      
      
      function arcBounds(cx,cy,radius,startAngle,endAngle){
        var minX=1000000;
        var minY=1000000;
        var maxX=-1000000;
        var maxY=-1000000;
      
        var possibleBoundingPoints=[]
        // centerpoint
        possibleBoundingPoints.push({x:cx,y:cy});
        // starting angle
        possibleBoundingPoints.push(arcpoint(cx,cy,radius,startAngle));
        // ending angle
        possibleBoundingPoints.push(arcpoint(cx,cy,radius,endAngle));
        // 0 radians
        if(0>=startAngle && 0<=endAngle){
          possibleBoundingPoints.push(arcpoint(cx,cy,radius,0));
        }
        // PI/2 radians
        var angle=PI/2;
        if(angle>=startAngle && angle<=endAngle){
          possibleBoundingPoints.push(arcpoint(cx,cy,radius,angle));
        }
        // PI radians
        var angle=PI;
        if(angle>=startAngle && angle<=endAngle){
          possibleBoundingPoints.push(arcpoint(cx,cy,radius,angle));
        }
        // PI*3/2 radians
        var angle=PI*3/2;
        if(angle>=startAngle && angle<=endAngle){
          possibleBoundingPoints.push(arcpoint(cx,cy,radius,angle));
        }
      
        for(var i=0;i<possibleBoundingPoints.length;i++){
          var pt=possibleBoundingPoints[i];
          if(pt.x<minX){minX=pt.x;}
          if(pt.y<minY){minY=pt.y;}
          if(pt.x>maxX){maxX=pt.x;}
          if(pt.y>maxY){maxY=pt.y;}
        }
      
        return({ x:minX, y:minY, width:maxX-minX, height:maxY-minY });
      
      }
      
      
      function arcpoint(cx,cy,radius,angle){
        var x=cx+radius*Math.cos(angle);
        var y=cy+radius*Math.sin(angle);
        return({x:x,y:y});
      }
      body{ background-color: ivory; }
      #canvas{border:1px solid blue;}
      &lt;canvas id="canvas" width=300 height=300&gt;&lt;/canvas&gt;

      【讨论】:

      • 您的解释非常详细而且很棒,我真的很感谢您的努力,我尝试将您的代码应用到我的弧上并调整所有参数,但边界框显示在不同的虽然位置不同的宽度和高度!!
      • @MahdiAlkhatib 某些角度无法正常工作:jsfiddle.net/ybpqmve0
      猜你喜欢
      • 2013-11-09
      • 1970-01-01
      • 2011-05-01
      • 2020-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多