草庐IT

javascript - 在多个点之间绘制扇形多边形

coder 2024-07-15 原文

我正在尝试在多个点之间使用 SVG 绘制扇形路径,就像为矩形绘制一样 here但在多个点之间。期望两个或更多两个或更多选择的点由扇形线连接。

但是我面临的问题是,

  1. 扇贝的大小不对称或随机。 - 我解决了这个问题
  2. 点击后多点扇贝方向和上下。如下图所示。

即使在 html5 canvas 上下文中给出答案,我也完全可以。我会做出调整。我缺少一些额外的计算,但无法弄清楚是什么。

请在结果页中多次点击查看当前绘制的扇贝

var strokeWidth = 3;

function distance(x1, y1, x2, y2) {
  return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

function findNewPoint(x, y, angle, distance) {
  var result = {};
  result.x = Math.round(Math.cos(angle) * distance + x);
  result.y = Math.round(Math.sin(angle) * distance + y);
  return result;
}

function getAngle(x1, y1, x2, y2) {
  return Math.atan2(y2 - y1, x2 - x1);
}

function scapolledLine(points, strokeWidth) {
  var that = this;
  var scallopSize = strokeWidth * 8;
  var path = [],
    newP = null;
  path.push("M", points[0].x, points[0].y);
  points.forEach(function(s, i) {
    var stepW = scallopSize,
      lsw = 0;
    var e = points[i + 1];
    if (!e) {
      path.push('A', stepW / 2, stepW / 2, "0 0 1", s.x, s.y);
      return;
    }
    var args = [s.x, s.y, e.x, e.y];
    var dist = that.distance.apply(that, args);
    if (dist === 0) return;
    var angle = that.getAngle.apply(that, args);
    newP = s;
    // Number of possible scallops between current points
    var n = dist / stepW,
      crumb;

    if (dist < (stepW * 2)) {
      stepW = (dist - stepW) > (stepW * 0.38) ? (dist / 2) : dist;
    } else {
      n = (n - (n % 1));
      crumb = dist - (n * stepW);
      /*if((stepW - crumb) > (stepW * 0.7)) {
          lsw = crumb;
      } else {
          stepW += (crumb / n);
      }*/
      stepW += (crumb / n);
    }

    // Recalculate possible scallops.
    n = dist / stepW;
    var aw = stepW / 2;
    for (var i = 0; i < n; i++) {
      newP = that.findNewPoint(newP.x, newP.y, angle, stepW);
      if (i === (n - 1)) {
        aw = (lsw > 0 ? lsw : stepW) / 2;
      }
      path.push('A', aw, aw, "0 0 1", newP.x, newP.y);
    }
    // scallopSize = stepW;
  });
  return path.join(' ');
  // return path.join(' ') + (points.length > 3 ? 'z' : '');
}

var points = [];
var mouse = null;
var dblclick = null,
  doneEnding = false;

window.test.setAttribute('stroke-width', strokeWidth);

function feed() {
  if (dblclick && doneEnding) return;
  if (!dblclick && (points.length > 0 && mouse)) {
    var arr = points.slice(0);
    arr.push(mouse);
    var str = scapolledLine(arr, strokeWidth);
    window.test.setAttribute('d', str);
  } else if (dblclick) {
    points.push(points[0]);
    doneEnding = true;
    var str = scapolledLine(points, strokeWidth);
    window.test.setAttribute('d', str);
  }
}

document.addEventListener('mousedown', function(event) {
  points.push({
    x: event.clientX,
    y: event.clientY
  });
  feed();
});

document.addEventListener('dblclick', function(event) {
  dblclick = true;
  feed();
});

document.addEventListener('mousemove', function(event) {
  if (points.length > 0) {
    mouse = {
      x: event.clientX,
      y: event.clientY
    }
    feed();
  }
});
body,
html {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0
}
svg {
  height: 100%;
  width: 100%
}
<svg id="svgP">
  <path id="test" style="stroke: RGBA(212, 50, 105, 1.00); fill: none" />
</svg>

最佳答案

寻找适合 3 个点的圆

此方法使用一个函数来找到适合 3 个点的圆。其中两个点是您拥有的点集。第 3 个点垂直于两点之间的线,并向外移动线段长度的一个因子。

找到圆后,找到从圆心点开始和结束的 Angular 以构成圆弧段,这样就完成了。只需使用 ctx.arc(

绘制弧线

我不确定你到底想要什么。我有它所以弧线都弯曲了,但是很容易绕过去。

如果您希望它们都具有相同的大小,则必须将这些点分隔为等距离,这非常简单,但很难适应给定区域。

演示

该演示可让您添加和拖动点。鼠标滚轮改变圆弧深度。

顶部的常量 arcDepth 决定每条弧的深度与线段长度的比较。这是一个分数。

您可以将其设置为以像素为单位的常量,请参阅 calcArc 以了解如何更改。

每条弧线都有独立的深度,因此如果您不喜欢重叠的弧线,请减少该弧线的深度(当然在代码中)。

希望对您有所帮助。

const pointSize = 4;
const pointCol = "#4AF";
var arcDepth = -0.5; // depth of arc as a factor of line seg length
                       // Note to have arc go the other (positive) way you have
                       // to change the ctx.arc draw call by adding anticlockwise flag 
                       // see drawArc for more
                       
const arcCol = "#4FA";
const arcWidth = 3;


// Find a circle that fits 3 points.
function fitCircleTo3P(p1x, p1y, p2x, p2y, p3x, p3y, arc) {
    var vx,
    vy,
    c,
    c1,
    u;

    c = (p2x - p1x) / (p1y - p2y); // slope of vector from vec 1 to vec 2
    c1 = (p3x - p2x) / (p2y - p3y); // slope of vector from vec 2 to vec 3
    // This will not happen in this example
    if (c === c1) { // if slope is the same they must be on the same line
        return null; // points are in a line
    }
    // locate the center
    if (p1y === p2y) { // special case with p1 and p2 have same y
        vx = (p1x + p2x) / 2;
        vy = c1 * vx + (((p2y + p3y) / 2) - c1 * ((p2x + p3x) / 2));
    } else
        if (p2y === p3y) { // special case with p2 and p3 have same y
            vx = (p2x + p3x) / 2;
            vy = c * vx + (((p1y + p2y) / 2) - c * ((p1x + p2x) / 2));
        } else {
            vx = ((((p2y + p3y) / 2) - c1 * ((p2x + p3x) / 2)) - (u = ((p1y + p2y) / 2) - c * ((p1x + p2x) / 2))) / (c - c1);
            vy = c * vx + u;
        }
    arc.x = vx;
    arc.y = vy;
    vx = p1x - vx;
    vy = p1y - vy;
    arc.rad = Math.sqrt(vx * vx + vy * vy);
    return arc;
}

var points = [];
var arcs = [];
function addArc(p1, p2, depth) {

    // remove next 5 line if you dont want all arcs to face the same way.
    if(points[p1][0] > points[p2][0]){
        var temp = p1;
        p1 = p2;
        p2 = temp;
    }
    var arc = {
        p1 : p1,
        p2 : p2,
        depth : depth,
        rad : null, // radius
        a1 : null, // angle from
        a2 : null, // angle to
        x : null,
        y : null,
    }
    arcs.push(arc);
    return arc;
}
function calcArc(arc, depth) {
    var p = points[arc.p1]; // get points
    var pp = points[arc.p2];
    // change depth if needed
    depth = arc.depth = depth !== undefined ? depth : arc.depth;
    var vx = pp[0] - p[0]; // vector from p to pp
    var vy = pp[1] - p[1];
    var cx = (pp[0] + p[0]) / 2; // center point
    var cy = (pp[1] + p[1]) / 2; // center point
    var len = Math.sqrt(vx * vx + vy * vy); // get length
    cx -= vy * depth; // find 3 point at 90 deg to line and dist depth
    cy += vx * depth;

    // To have depth as a fixed length uncomment 4 lines below and comment out 2 lines above.
    //var nx = vx / len;  // normalise vector
    //var ny = vy / len;
    //cx -= ny * depth; // find 3 point at 90 deg to line and dist depth
    //cy += nx * depth;


    fitCircleTo3P(p[0], p[1], cx, cy, pp[0], pp[1], arc); // get the circle that fits
    arc.a1 = Math.atan2(p[1] - arc.y, p[0] - arc.x); // get angle from circle center to first point
    arc.a2 = Math.atan2(pp[1] - arc.y, pp[0] - arc.x); // get angle from circle center to second point

}
function addPoint(x, y) {
    points.push([x, y]);
}
function drawPoint(x, y, size, col) {
    ctx.fillStyle = col;
    ctx.beginPath();
    ctx.arc(x, y, size, 0, Math.PI * 2);
    ctx.fill();
}

function drawArc(arc, width, col) {
    ctx.lineCap = "round";
    ctx.strokeStyle = col;
    ctx.lineWidth = width;
    ctx.beginPath();
    ctx.arc(arc.x, arc.y, arc.rad, arc.a1, arc.a2,false);  // true for anti clock wise
    ctx.stroke();
}
function findClosestPoint(x, y, dist) {
    var index = -1;
    for (var i = 0; i < points.length; i++) {
        var p = points[i];
        var vx = x - p[0];
        var vy = y - p[1];
        var d = Math.sqrt(vx * vx + vy * vy);
        if (d < dist) {
            dist = d;
            index = i;
        }
    }
    return index;
}

var dragging = false;
var drag = -1;
var dragX, dragY;
var recalcArcs = false;
function display() {
    ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
    ctx.globalAlpha = 1; // reset alpha
    ctx.clearRect(0, 0, w, h);
    if(mouse.w > 0){
        arcDepth *= 1.05;
        mouse.w = 0;
        recalcArcs = true;
    }
    if(mouse.w < 0){
        arcDepth *= 1/1.05;
        mouse.w = 0;
        recalcArcs = true;
    }
       
    if (mouse.buttonRaw & 1) {

        if (!dragging) {
            var i = findClosestPoint(mouse.x, mouse.y, pointSize * 3);
            if (i > -1) {
                drag = i;
                dragging = true;
                dragX = mouse.x - points[drag][0];
                dragY = mouse.y - points[drag][1];
            }
        }
        if (dragging) {
            points[drag][0] = mouse.x - dragX
                points[drag][1] = mouse.y - dragY
                recalcArcs = true;

        } else {
            addPoint(mouse.x, mouse.y);
            if (points.length > 1) {
                calcArc(addArc(points.length - 2, points.length - 1, arcDepth));
            }
            mouse.buttonRaw = 0;
        }

    } else {
        if (dragging) {
            dragging = false;
            drag = -1;
            recalcArcs = true;
        }
        var i = findClosestPoint(mouse.x, mouse.y, pointSize * 3);
        if (i > -1) {
            canvas.style.cursor = "move";
        } else {
            canvas.style.cursor = "default";

        }
    }
    for (var i = 0; i < arcs.length; i++) {
        if (recalcArcs) {
            calcArc(arcs[i],arcDepth);
        }
        drawArc(arcs[i], arcWidth, arcCol);

    }
    recalcArcs = false;

    for (var i = 0; i < points.length; i++) {
        var p = points[i];
        drawPoint(p[0], p[1], pointSize, pointCol);
    }

}


//===========================================================================================
// END OF ANSWER

// Boiler plate code from here down. Does mouse,canvas,resize and what not
var w, h, cw, ch, canvas, ctx, mouse, globalTime = 0, firstRun = true; ;
(function () {
    const RESIZE_DEBOUNCE_TIME = 100;
    var createCanvas,
    resizeCanvas,
    setGlobals,
    resizeCount = 0;
    createCanvas = function () {
        var c,
        cs;
        cs = (c = document.createElement("canvas")).style;
        cs.position = "absolute";
        cs.top = cs.left = "0px";
        cs.zIndex = 1000;
        document.body.appendChild(c);
        return c;
    }
    resizeCanvas = function () {
        if (canvas === undefined) {
            canvas = createCanvas();
        }
        canvas.width = innerWidth;
        canvas.height = innerHeight;
        ctx = canvas.getContext("2d");
        if (typeof setGlobals === "function") {
            setGlobals();
        }
        if (typeof onResize === "function") {
            if (firstRun) {
                onResize();
                firstRun = false;
            } else {
                resizeCount += 1;
                setTimeout(debounceResize, RESIZE_DEBOUNCE_TIME);
            }
        }
    }
    function debounceResize() {
        resizeCount -= 1;
        if (resizeCount <= 0) {
            onResize();
        }
    }
    setGlobals = function () {
        cw = (w = canvas.width) / 2;
        ch = (h = canvas.height) / 2;
    }
    mouse = (function () {
        function preventDefault(e) {
            e.preventDefault();
        }
        var mouse = {
            x : 0,
            y : 0,
            w : 0,
            alt : false,
            shift : false,
            ctrl : false,
            buttonRaw : 0,
            over : false,
            bm : [1, 2, 4, 6, 5, 3],
            active : false,
            bounds : null,
            crashRecover : null,
            mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",")
        };
        var m = mouse;
        function mouseMove(e) {
            var t = e.type;
            m.bounds = m.element.getBoundingClientRect();
            m.x = e.pageX - m.bounds.left;
            m.y = e.pageY - m.bounds.top;
            m.alt = e.altKey;
            m.shift = e.shiftKey;
            m.ctrl = e.ctrlKey;
            if (t === "mousedown") {
                m.buttonRaw |= m.bm[e.which - 1];
            } else if (t === "mouseup") {
                m.buttonRaw &= m.bm[e.which + 2];
            } else if (t === "mouseout") {
                m.buttonRaw = 0;
                m.over = false;
            } else if (t === "mouseover") {
                m.over = true;
            } else if (t === "mousewheel") {
                m.w = e.wheelDelta;
            } else if (t === "DOMMouseScroll") {
                m.w = -e.detail;
            }
            e.preventDefault();
        }
        m.start = function (element) {
            if (m.element !== undefined) {
                m.removeMouse();
            }
            m.element = element === undefined ? document : element;
            m.mouseEvents.forEach(n => {
                m.element.addEventListener(n, mouseMove);
            });
            m.element.addEventListener("contextmenu", preventDefault, false);
            m.active = true;
        }
        m.remove = function () {
            if (m.element !== undefined) {
                m.mouseEvents.forEach(n => {
                    m.element.removeEventListener(n, mouseMove);
                });
                m.element.removeEventListener("contextmenu", preventDefault);
                m.element = m.callbacks = undefined;
                m.active = false;
            }
        }
        return mouse;
    })();


    function update(timer) { // Main update loop
        if (ctx === undefined) {
            return;
        }
        globalTime = timer;
        display(); // call demo code
        requestAnimationFrame(update);
    }
    setTimeout(function () {
        resizeCanvas();
        mouse.start(canvas, true);
        window.addEventListener("resize", resizeCanvas);
        requestAnimationFrame(update);
    }, 0);
})();
Left click to add point. Left click drag to move points.<br>
Mouse wheel changes arc depth.

拿两个...

也许这就是您想要的。抱歉,由于我现在时间不够,所以有点乱。

与之前相同的代码只是将点添加到框的外部,确保宽度和高度步距与边缘的间距相等。

const pointSize = 4;
const pointCol = "#4AF";
var arcDepth = -0.5; // depth of arc as a factor of line seg length
                       // Note to have arc go the other (positive) way you have
                       // to change the ctx.arc draw call by adding anticlockwise flag 
                       // see drawArc for more
                       
const arcCol = "#F92";
const arcWidth = 8;


// Find a circle that fits 3 points.
function fitCircleTo3P(p1x, p1y, p2x, p2y, p3x, p3y, arc) {
    var vx,
    vy,
    c,
    c1,
    u;

    c = (p2x - p1x) / (p1y - p2y); // slope of vector from vec 1 to vec 2
    c1 = (p3x - p2x) / (p2y - p3y); // slope of vector from vec 2 to vec 3
    // This will not happen in this example
    if (c === c1) { // if slope is the same they must be on the same line
        return null; // points are in a line
    }
    // locate the center
    if (p1y === p2y) { // special case with p1 and p2 have same y
        vx = (p1x + p2x) / 2;
        vy = c1 * vx + (((p2y + p3y) / 2) - c1 * ((p2x + p3x) / 2));
    } else
        if (p2y === p3y) { // special case with p2 and p3 have same y
            vx = (p2x + p3x) / 2;
            vy = c * vx + (((p1y + p2y) / 2) - c * ((p1x + p2x) / 2));
        } else {
            vx = ((((p2y + p3y) / 2) - c1 * ((p2x + p3x) / 2)) - (u = ((p1y + p2y) / 2) - c * ((p1x + p2x) / 2))) / (c - c1);
            vy = c * vx + u;
        }
    arc.x = vx;
    arc.y = vy;
    vx = p1x - vx;
    vy = p1y - vy;
    arc.rad = Math.sqrt(vx * vx + vy * vy);
    return arc;
}

var points = [];
var arcs = [];
function addArc(p1, p2, depth) {
    var arc = {
        p1 : p1,
        p2 : p2,
        depth : depth,
        rad : null, // radius
        a1 : null, // angle from
        a2 : null, // angle to
        x : null,
        y : null,
    }
    arcs.push(arc);
    return arc;
}
function calcArc(arc, depth) {
    var p = points[arc.p1]; // get points
    var pp = points[arc.p2];
    // change depth if needed
    depth = arc.depth = depth !== undefined ? depth : arc.depth;
    var vx = pp[0] - p[0]; // vector from p to pp
    var vy = pp[1] - p[1];
    var cx = (pp[0] + p[0]) / 2; // center point
    var cy = (pp[1] + p[1]) / 2; // center point
    var len = Math.sqrt(vx * vx + vy * vy); // get length
    cx -= vy * depth; // find 3 point at 90 deg to line and dist depth
    cy += vx * depth;

    // To have depth as a fixed length uncomment 4 lines below and comment out 2 lines above.
    //var nx = vx / len;  // normalise vector
    //var ny = vy / len;
    //cx -= ny * depth; // find 3 point at 90 deg to line and dist depth
    //cy += nx * depth;


    fitCircleTo3P(p[0], p[1], cx, cy, pp[0], pp[1], arc); // get the circle that fits
    arc.a1 = Math.atan2(p[1] - arc.y, p[0] - arc.x); // get angle from circle center to first point
    arc.a2 = Math.atan2(pp[1] - arc.y, pp[0] - arc.x); // get angle from circle center to second point

}
function addPoint(x, y) {
    points.push([x, y]);
}
function drawPoint(x, y, size, col) {
    ctx.fillStyle = col;
    ctx.beginPath();
    ctx.arc(x, y, size, 0, Math.PI * 2);
    ctx.fill();
}
function drawArcStart(width,col){
    ctx.lineCap = "round";
    ctx.strokeStyle = col;
    ctx.lineJoin = "round";
    ctx.lineWidth = width;
    ctx.beginPath();
    
}
function drawArc(arc){
    ctx.arc(arc.x,arc.y,arc.rad,arc.a1,arc.a2);
}    
function drawArcDone(){
    ctx.closePath();
    ctx.stroke();
}
function findClosestPoint(x, y, dist) {
    var index = -1;
    for (var i = 0; i < points.length; i++) {
        var p = points[i];
        var vx = x - p[0];
        var vy = y - p[1];
        var d = Math.sqrt(vx * vx + vy * vy);
        if (d < dist) {
            dist = d;
            index = i;
        }
    }
    return index;
}

var dragging = false;
var drag = -1;
var dragX, dragY;
var recalcArcs = false;
var box;
//========================================================================
// New box code from her down

// creates the box when canvas is ready
var onResize = function(){
    box = {
        x : canvas.width * (1/8),
        y : canvas.height * (1/8),
        w : canvas.width * (6/8),
        h : canvas.height * (6/8),
        recalculate : true,
        arcCount : 20, // number of arcs to try and fit. Does not mean that it will happen
    }
}

function display() {
    ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
    ctx.globalAlpha = 1; // reset alpha
    ctx.clearRect(0, 0, w, h);

if(mouse.w !== 0){
    if(mouse.buttonRaw & 4){ // change arc depth
        if(mouse.w < 0){
            arcDepth *= 1/1.05;
        }else{
            arcDepth *= 1.05;
        }
        recalcArcs = true;
        
    }else{  // change arc count
        box.arcCount += Math.sign(mouse.w);
        box.arcCount = Math.max(4,box.arcCount);
        box.recalculate = true;
    }
    mouse.w = 0;
}
// drag out box;
if(mouse.buttonRaw & 1){
    if(!dragging){
        box.x = mouse.x;
        box.y = mouse.y;
        dragging = true;
    }
    box.w = mouse.x - box.x;
    box.h = mouse.y - box.y;
    box.recalculate = true;
    if(box.w <0){
        box.x = box.x + box.w;
        box.w = - box.w;
    }
    if(box.h <0){
        box.y = box.y + box.h;
        box.h = - box.h;
    }
}else{
    dragging = false;
}
// stop error
if(box.w === 0 || box.h === 0){
    box.recaculate = false;
}

// caculate box arcs
if(box.recalculate){
    // reset arrays
    points.length = 0;
    arcs.length = 0;
    // get perimiter length
    var perimLen = (box.w + box.h)* 2;
    // get estimated step size
    var step = perimLen / box.arcCount;
    // get inset size for width and hight
    var wInStep = (box.w - (Math.floor(box.w/step)-1)*step) / 2;
    var hInStep = (box.h - (Math.floor(box.h/step)-1)*step) / 2;
    // fix if box to narrow
    if(box.w < step){
        wInStep = 0;
        hInStep = 0;
        step = box.h / (Math.floor(box.h/step));
    }else if(box.h < step){
        wInStep = 0;
        hInStep = 0;
        step = box.w / (Math.floor(box.w/step));
        
    }
    
    // Add points clock wise
    var x = box.x + wInStep;
    while(x < box.x + box.w){ // across top
        addPoint(x,box.y);
        x += step;
    }
    var y = box.y + hInStep; 
    while(y < box.y + box.h){ // down right side
        addPoint(box.x + box.w,y);
        y += step;
    }
    x = box.x + box.w - wInStep;
    while(x > box.x){          // left along bottom
        addPoint(x,box.y + box.h);
        x -= step;
    }
    var y = box.y + box.h - hInStep;
    while(y > box.y){  // up along left side
        addPoint(box.x,y);
        y -= step;
    }
    // caculate arcs.
    for(var i =0; i <points.length; i++){
        calcArc(addArc(i,(i + 1) % points.length,arcDepth));
    }
    box.recalculate = false;
}
// recaculate arcs if needed
for(var i = 0; i < arcs.length; i ++){
    if(recalcArcs){
        calcArc(arcs[i],arcDepth);
    }
}
// draw arcs
drawArcStart(arcWidth,arcCol)
for(var i = 0; i < arcs.length; i ++){
    drawArc(arcs[i]);
}
drawArcDone();
recalcArcs = false;
}


//===========================================================================================
// END OF ANSWER

// Boiler plate code from here down. Does mouse,canvas,resize and what not
var w, h, cw, ch, canvas, ctx, mouse, globalTime = 0, firstRun = true; ;
(function () {
    const RESIZE_DEBOUNCE_TIME = 100;
    var createCanvas,
    resizeCanvas,
    setGlobals,
    resizeCount = 0;
    createCanvas = function () {
        var c,
        cs;
        cs = (c = document.createElement("canvas")).style;
        cs.position = "absolute";
        cs.top = cs.left = "0px";
        cs.zIndex = 1000;
        document.body.appendChild(c);
        return c;
    }
    resizeCanvas = function () {
        if (canvas === undefined) {
            canvas = createCanvas();
        }
        canvas.width = innerWidth;
        canvas.height = innerHeight;
        ctx = canvas.getContext("2d");
        if (typeof setGlobals === "function") {
            setGlobals();
        }
        if (typeof onResize === "function") {
            if (firstRun) {
                onResize();
                firstRun = false;
            } else {
                resizeCount += 1;
                setTimeout(debounceResize, RESIZE_DEBOUNCE_TIME);
            }
        }
    }
    function debounceResize() {
        resizeCount -= 1;
        if (resizeCount <= 0) {
            onResize();
        }
    }
    setGlobals = function () {
        cw = (w = canvas.width) / 2;
        ch = (h = canvas.height) / 2;
    }
    mouse = (function () {
        function preventDefault(e) {
            e.preventDefault();
        }
        var mouse = {
            x : 0,
            y : 0,
            w : 0,
            alt : false,
            shift : false,
            ctrl : false,
            buttonRaw : 0,
            over : false,
            bm : [1, 2, 4, 6, 5, 3],
            active : false,
            bounds : null,
            crashRecover : null,
            mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",")
        };
        var m = mouse;
        function mouseMove(e) {
            var t = e.type;
            m.bounds = m.element.getBoundingClientRect();
            m.x = e.pageX - m.bounds.left;
            m.y = e.pageY - m.bounds.top;
            m.alt = e.altKey;
            m.shift = e.shiftKey;
            m.ctrl = e.ctrlKey;
            if (t === "mousedown") {
                m.buttonRaw |= m.bm[e.which - 1];
            } else if (t === "mouseup") {
                m.buttonRaw &= m.bm[e.which + 2];
            } else if (t === "mouseout") {
                m.buttonRaw = 0;
                m.over = false;
            } else if (t === "mouseover") {
                m.over = true;
            } else if (t === "mousewheel") {
                m.w = e.wheelDelta;
            } else if (t === "DOMMouseScroll") {
                m.w = -e.detail;
            }
            e.preventDefault();
        }
        m.start = function (element) {
            if (m.element !== undefined) {
                m.removeMouse();
            }
            m.element = element === undefined ? document : element;
            m.mouseEvents.forEach(n => {
                m.element.addEventListener(n, mouseMove);
            });
            m.element.addEventListener("contextmenu", preventDefault, false);
            m.active = true;
        }
        m.remove = function () {
            if (m.element !== undefined) {
                m.mouseEvents.forEach(n => {
                    m.element.removeEventListener(n, mouseMove);
                });
                m.element.removeEventListener("contextmenu", preventDefault);
                m.element = m.callbacks = undefined;
                m.active = false;
            }
        }
        return mouse;
    })();


    function update(timer) { // Main update loop
        if (ctx === undefined) {
            return;
        }
        globalTime = timer;
        display(); // call demo code
        requestAnimationFrame(update);
    }
    setTimeout(function () {
        resizeCanvas();
        mouse.start(canvas, true);
        window.addEventListener("resize", resizeCanvas);
        requestAnimationFrame(update);
    }, 0);
})();
Left click drag to create a box<br>Mouse wheel to change arc count<br>Hold right button down and wheel to change arc depth.<br>

关于javascript - 在多个点之间绘制扇形多边形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40941859/

有关javascript - 在多个点之间绘制扇形多边形的更多相关文章

  1. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  2. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  3. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  4. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  5. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  6. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  7. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  8. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

  9. ruby - 使用多个数组创建计数 - 2

    我正在尝试按0-9和a-z的顺序创建数字和字母列表。我有一组值value_array=['0','1','2','3','4','5','6','7','8','9','a','b','光盘','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','','u','v','w','x','y','z']和一个组合列表的数组,按顺序,这些数字可以产生x个字符,比方说三个list_array=[]和一个当前字母和数字组合的数组(在将它插入列表数组之前我会把它变成一个字符串,]current_combo['0','0','0']

  10. ruby-on-rails - before_filter 运行多个方法 - 2

    是否有可能:before_filter:authenticate_user!||:authenticate_admin! 最佳答案 before_filter:do_authenticationdefdo_authenticationauthenticate_user!||authenticate_admin!end 关于ruby-on-rails-before_filter运行多个方法,我们在StackOverflow上找到一个类似的问题: https://

随机推荐