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

Exc*_*ion 9 javascript svg html5-canvas

我试图在多个点之间使用SVG绘制扇形路径,就像它在这里绘制矩形但在多个点之间绘制.期望通过扇形线连接两个或更多两个或更多个选定点.

但我面临的问题是,

  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();
  }
});
Run Code Online (Sandbox Code Playgroud)
body,
html {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0
}
svg {
  height: 100%;
  width: 100%
}
Run Code Online (Sandbox Code Playgroud)
<svg id="svgP">
  <path id="test" style="stroke: RGBA(212, 50, 105, 1.00); fill: none" />
</svg>
Run Code Online (Sandbox Code Playgroud)

Con*_*Fan 3

以下代码片段通过分析相邻线段来确定每个线段的方向(CW、CCW)。对于线段A,如果两个相邻线段都在A的同一侧(或者如果A只有一个相邻线段),则不存在歧义,并且线段A的扇贝位于由这些线段形成的凸形状的外侧。然而,如果相邻线段位于 A 的相对侧,则在锯齿形图案中,选择距离线段 A 延伸最远的相邻线段来设置线段 A 的方向。

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 getSeparationFromLine(lineOrigin, lineAngle, pt) {
    x = pt.x - lineOrigin.x;
    y = pt.y - lineOrigin.y;
    return -x * Math.sin(lineAngle) + y * Math.cos(lineAngle);
}

function getDirection(pts, index, closed) {
    var last = pts.length - 1;
    var start = index;
    var end = (closed && start == last) ? 0 : index + 1;
    var prev = (closed && start == 0) ? last : start - 1;
    var next = (closed && end == last) ? 0 : end + 1;

    var isValidSegment = 0 <= start && start <= last && 0 <= end && end <= last && end !== start;

    if (!isValidSegment) {
        return 1;
    }

    var pt1 = pts[start];
    var pt2 = pts[end];

    var pt, x, y;
    var ccw = 0.0;
    var theta = Math.atan2(pt2.y - pt1.y, pt2.x - pt1.x);

    if (0 <= prev && prev <= last) {
        ccw += getSeparationFromLine(pt1, theta, pts[prev]);
    }

    if (0 <= next && next <= last) {
        ccw += getSeparationFromLine(pt1, theta, pts[next]);
    }

    return ccw > 0 ? "1" : "0";
}

function scapolledLine(pts, closed, strokeWidth) {
    var that = this;
    var scallopSize = strokeWidth * 8;
    var lastIndex = pts.length - 1;
    var path = [], newP = null;
    path.push("M", pts[0].x, pts[0].y);

    pts.forEach(function (s, currentIndex) {
        var stepW = scallopSize, lsw = 0;
        var isClosingSegment = closed && currentIndex == lastIndex;
        var nextIndex = isClosingSegment ? 0 : currentIndex + 1;
        var e = pts[nextIndex];
        if (!e) {
            return;
        }

        var direction = getDirection(pts, currentIndex, closed);
        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 pts
        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);
            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 " + direction, newP.x, newP.y);
        }

        if (isClosingSegment) {
            path.push('A', stepW / 2, stepW / 2, "0 0 " + direction, e.x, e.y);
        }
    });
    return path.join(' ');
}

var strokeWidth = 3;
var points = [];
var mouse = null;
var isClosed = false;

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

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

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

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

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