简体   繁体   English

在圆扇形中绘制随机点

[英]plotting random points in circle sector

I have a pie chart in canvas and I wanted to plot random points in each sector of that pie. 我在画布上有一个饼图,我想在该饼的每个扇区中绘制随机点。

I have got the area of each sector. 我已经了解了每个部门的领域。 using the arc sector 使用弧扇

var arcsector = Math.PI * (2 * sector / total);
var startAngle = (lastend - offset) * (radius/Math.PI);
var endAngle = (lastend + arcsector - offset) * (radius/Math.PI);
var sectorAngle = arcsector * (radius/Math.PI);
var sectorArea = .5 * (sectorAngle*Math.PI/180) * (radius*radius);

How can I randomly plot points within that area? 如何在该区域内随机绘制点?

The simple approach is to: 简单的方法是:

  • Create a temporary arc shape on path 在路径上创建临时弧形
  • Create a random point 创建一个随机点
  • Hit-test the point against the shape and plot if inside 对形状进行碰撞测试并在内部绘制

You can create a temporary arc path by doing something like this (adjust to match your situation) (and no need to stroke/fill): 您可以通过执行以下操作(调整以适合您的情况)来创建临时弧路径(无需描边/填充):

ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(cx, cy, radius, startAngle, endAngle);
ctx.closePath();

Then create random points within the bounds of that arc, or just use a very basic approach (which is probably fast enough in most case unless you would need a lot of points) - and the spread is even compared to using a radius based approach: 然后在该弧的边界内创建随机点,或仅使用一种非常基本的方法(在大多数情况下,除非您需要很多点,否则这可能足够快)– 甚至与使用基于半径的方法相比,展宽也是如此

var randomX = cx + radius * 2 * Math.random() - radius;
var randomY = cy + radius * 2 * Math.random() - radius;

and finally hit-test: 最后进行测试:

if (ctx.isPointInPath(randomX, randomY)) {
    // plot point, count etc.
}

FIDDLE 小提琴

Update 更新

An even more efficient way to generate random points in the arc shape (and spread them more even) is to draw directly to an off-screen canvas without using any bound checking and no cos/sin operations, which are expensive, and finally composite that on top of your arc shape (or use arc as clip). 生成弧形随机点(并使它们均匀分布)的更有效方法是直接绘制到屏幕外画布,而无需使用任何边界检查和无余弦/正弦运算,这很昂贵,最后将其合成在圆弧形状的顶部(或使用圆弧作为剪辑)。

// create off-screen canvas
var ocanvas = document.createElement('canvas');
var octx = ocanvas.getContext('2d');
var d;
d = ocanvas.width = ocanvas.height = 300;

octx.fillStyle = '#fff';

while(count) {
    var randomX = d * Math.random();
    var randomY = d * Math.random();
    octx.fillRect(randomX - 1, randomY - 1, 2, 2);
    count--;
}

// composite random points with main arc    
ctx.globalCompositeOperation = 'source-atop';
ctx.drawImage(ocanvas, 0, 0);
ctx.globalCompositeOperation = 'source-over';

It can be optimized further by having the off-screen canvas represent only the bounds of the arc shape. 通过使屏幕外画布仅代表弧形的边界,可以进一步优化它。

FIDDLE 小提琴

A pie is a part of a circle, which, with your notations, starts at startAngle and ends at endAngle. 馅饼是圆的一部分,用您的符号表示,圆从startAngle开始,在endAngle结束。

Most simple way to get a random point is to build a random angle (between startAngle and endAngle) and a random radius, then you have your point with those lines : 获取随机点的最简单方法是建立一个随机角度(介于startAngle和endAngle之间)和随机半径,然后将这些点与这些线对齐:

 var randAngle  = startAngle + Math.random()*( endAngle - startAngle );
 var randRadius = Math.random()*radius;
 var randX = centerX + randRadius * Math.cos(randAngle);
 var randY = centerY + randRadius * Math.sin(randAngle);
 ctx.fillRect ( randX, randY, 1, 1 ) ;

repeat the number of times required ! 重复所需次数!

Demo: http://jsfiddle.net/jv6nP/3/ 演示: http //jsfiddle.net/jv6nP/3/

it's not perfect that points are at border and thus their radius being bigger than zero makes them overlap onto other parts of pie. 点在边界处并不完美,因此它们的半径大于零会使它们重叠到饼图的其他部分。 And this also results in them going over black border. 这也导致它们越过黑色边框。

var can = $('#can')[0].getContext('2d'), 
    border=2, 
    x=100, 
    y=75, 
    r=60, 
    sRadius= 0,
    leadAngle=null, 
    points= [], 
    dotRadius=2,
    data = {
        water:[30,'#5CC5FA'],
        earth:[60,'#F0A71F'],
        air:[10,'#26EDE3']
    };



function reDraw(){

    //making border...
    can.beginPath();
    can.arc(x,y,r+border,0,2*Math.PI);
    can.fillStyle='black';
    can.fill();


var newAngle=null;
for (var k in data) { //making piechart..

    leadAngle = (2*Math.PI)*(data[k][0]/100);
    newAngle = sRadius+leadAngle;

    calPoints(sRadius,leadAngle,k);

    can.beginPath();
    can.arc(x,y,r,sRadius,newAngle);
    can.lineTo(x,y);
    can.fillStyle=data[k][1];
    can.fill();
    sRadius= newAngle;
}

//calculating points..
function calPoints(s,e,name) {
    if (name!='water') return;
    var py,px,rAngle,rRad;
    for (var i=0; i<15; i++) {
         rAngle=s+Math.random()*(e);
         rRad = Math.random()*r;
         px = (Math.cos(rAngle) * rRad)+x;
         py = (Math.sin(rAngle) * rRad)+y;
         points.push([px,py]);
    }
}


//plotting dots from data...
points.forEach(function(v){
        can.beginPath();
        can.arc(v[0],v[1],dotRadius,0,2*Math.PI);
        can.fillStyle='fff';
        can.fill();
});

    points=[];
    requestAnimationFrame(reDraw);

}

reDraw();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM