snap-test

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
<svg id="debug" width="300" height="300"></svg>
<svg id="svg" width="300" height="300"></svg>
<div id="output">

</div>

JavaScript 1.7

function Node(center, angle, radius) {
	/*
  * 计算每个节点的坐标和2个控制点的坐标
  * 取控制节点距离为 1/4 半径
  */
  let PI_2 = Math.PI / 2

	var dx = radius * Math.cos(angle)
  var dy = radius * Math.sin(angle)
  var node = [center[0] + dx, center[1] + dy]
  var contoller_radius = radius / 4
  
  dx = contoller_radius * Math.cos(angle - PI_2)
  dy = contoller_radius * Math.sin(angle - PI_2)
  var controller1 = [node[0] + dx, node[1] + dy]
  
  dx = contoller_radius * Math.cos(angle + PI_2)
  dy = contoller_radius * Math.sin(angle + PI_2)
  var controller2 = [node[0] + dx, node[1] + dy]
  
  return {
    node: node,
    controller1: controller1,
    controller2: controller2
  }
}

function generateNodes(width, node_count, radius){

  // calc
  var angle = Math.PI * 2 / node_count
  var center = [width / 2, width / 2]
  var nodes = []
  for (var i = 0; i < node_count; ++i) {
    nodes.push(new Node(center, angle * i, radius))
  }
  return nodes
}

function debugNodes(selector, nodes) {
  var s = Snap(selector);
  var d = `M ${nodes[0].node[0]} ${nodes[0].node[1]} `
  for(i = 0; i < nodes.length; ++i) {
    var node = nodes[(i + 1) % nodes.length]
    d += `L ${node.node[0]} ${node.node[1]} `
    s.line(node.controller1[0], node.controller1[1], node.controller2[0], node.controller2[1]).attr({stroke: "#f82653",strokeWidth: 1 });
  }
  s.path(d).attr({fill: "#cccccc", stroke: "#339ce1", strokeWidth: 2});
}

function generateSVG(selector, nodes) {
	/* 根据所有节点以及控制点生成三次贝塞尔曲线
  * 首先 M到第一个节点,然后依次 按照 "C 当前节点的控制节点2 下个节点的控制节点1 下个节点"
  * 参数 生成 Path 的路径
  */
  var s = Snap(selector);
  var d = `M ${nodes[0].node[0]} ${nodes[0].node[1]} `
  for(i = 0; i < nodes.length; ++i) {
    var node1 = nodes[i]
    var node2 = nodes[(i + 1) % nodes.length]
    d += `C ${node1.controller2[0]} ${node1.controller2[1]} ${node2.controller1[0]} ${node2.controller1[1]} ${node2.node[0]} ${node2.node[1]} `
  }
  s.path(d).attr({fill: "#339ce1",stroke: "#339ce1",strokeWidth: 2});
  return s
}

var nodes =...