2016-10-12 131 views
1

我正在制作Mike Bostock的collapsible tree的径向版本。D3.js径向可折叠径向树(每个分支有1个分支)

我想有一个分支的每组分支而不是每个元素的分支。

这是我到目前为止有: enter image description here

JSFiddle我目前的表现是here

var flare中的额外注释行只是用于密度测试的额外行,以便查看它的外观如何与大量信息一致。

白色圆圈用于隐藏根元素和白色背景上第一级的链接。要删除它,只需删除以下行:

var circle = svg.append("circle") 
    .attr("cx", 0) 
    .attr("cy", 0) 
    .attr("r", radius - 5) 
    .style("fill", "white"); 

下面是我想要的有: enter image description here

从根本工作原理为1级不要紧,只要1级元素形成一个圆圈(这里有3个1级元素),因为我仍然将级别0(根)隐藏到级别1

但是,重要的是父元素的间距根据被折叠的子元素而改变,或者不。

回答

2

这是我对你的插图。实质上,它是一个非常自定义的路径生成器。我试图评论它,所以让我知道你是否有任何问题。

link.transition() 
    .duration(duration) 
    .attr("d", function(d) { 

     // depth zero, don't draw, this is your "hidden" links 
     if (d.source.depth === 0) return ""; 

     // if we have children 
     if (d.source.children) { 

     // sum the angles to find the midpoint of the children 
     var pad = 20, //<-- pad is the step off distance to children 
      sum = 0; 
     d.source.children.forEach(function(c) { 
      sum += c.x; 
     }); 

     // this is the mid point position 
     var ma = ((sum/d.source.children.length) - 90) * (Math.PI/180), 
      mr = d.source.children[0].y - pad, 
      mid = [mr * Math.cos(ma), mr * Math.sin(ma)]; //x,y position 

     // this is the source position 
     var sa = (d.source.x - 90) * (Math.PI/180), 
      sr = d.source.y - pad, 
      source = [sr * Math.cos(sa), sr * Math.sin(sa)]; 

     // this is the final target position 
     var ta = (d.target.x - 90) * (Math.PI/180), 
      tr = d.target.y - pad, 
      target = [tr * Math.cos(ta), tr * Math.sin(ta)]; 

     // this is the arc from mid to target 
     var dx = target[0] - source[0], 
      dy = target[1] - source[1], 
      dr = Math.sqrt(dx * dx + dy * dy); 

     // this is the line from the source, to the mid and arced to children 
     return "M" + source + 
      "L" + mid + 
      "A" + dr + "," + dr + " 0 0," + (ma < ta ? 1 : 0) + " " + target[0] + "," + target[1]; 
     } 
    }); 

更新的小提琴here

的更新备注

检查此版本出来。它会删除我写的自定义弧,而使用d3.svg.arc生成器。它还将绘图限制为仅删除冗余路径的第一个和最后一个孩子。

<!DOCTYPE html> 
 
<html> 
 

 
<head> 
 
    <style> 
 
    .node { 
 
     cursor: pointer; 
 
    } 
 
    
 
    .node circle { 
 
     fill: #fff; 
 
     stroke: steelblue; 
 
     stroke-width: 1.5px; 
 
    } 
 
    
 
    .node text { 
 
     font: 10px sans-serif; 
 
    } 
 
    
 
    .link { 
 
     fill: none; 
 
     stroke: #ccc; 
 
     stroke-width: 1.5px; 
 
    } 
 
    
 
    #svg { 
 
     height: 500px; 
 
     width: 500px; 
 
    } 
 
    </style> 
 
</head> 
 

 
<body> 
 
    <script src="//d3js.org/d3.v3.min.js"></script> 
 
    <div id="svg"></div> 
 
    <script> 
 
    flare = { 
 
     "name": "root", 
 
     "children": [{ 
 
      "name": "item1", 
 
      "children": [{ 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item2" 
 
      }, { 
 
      "name": "item3" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, 
 

 
     { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, { 
 
      "name": "item4", 
 
      "children": [{ 
 
      "name": "item5" 
 
      }, { 
 
      "name": "item6" 
 
      }, { 
 
      "name": "item7" 
 
      }] 
 
     }, 
 

 
     { 
 
      "name": "item8", 
 
      "children": [{ 
 
      "name": "item9" 
 
      }, { 
 
      "name": "item10" 
 
      }] 
 
     } 
 
     ] 
 
    }; 
 

 
    //variables used to modify some basic properties of the svg elements 
 
    var divHeight = document.getElementById('svg').offsetHeight; 
 
    var divWidth = document.getElementById('svg').clientWidth; 
 
    var radius = 75; 
 
    var separation = 2; 
 

 
    var diameter = 800; 
 

 
    var margin = { 
 
     top: 20, 
 
     right: 120, 
 
     bottom: 20, 
 
     left: 120 
 
     }, 
 
     width = diameter, 
 
     height = diameter; 
 

 
    var i = 0, 
 
     duration = 350, 
 
     root; 
 

 
    var tree = d3.layout.tree() 
 
     .size([360, diameter/2 - 80]) 
 
     .separation(function(a, b) { 
 
     return (a.parent == b.parent ? 1 : separation)/a.depth; 
 
     }); 
 
    //last line is the separation between branches of the tree when clicked 
 

 
    var diagonal = d3.svg.line.radial(); 
 
    // .projection(function(d) { var r = d.y, a = (d.x - 90)/180 * Math.PI; 
 
    // return [r * Math.cos(a), r * Math.sin(a)]; }); 
 

 
    var svg = d3.select("#svg").append("svg") 
 
     //.attr("width", width) 
 
     //.attr("height", height) 
 
     .attr("width", divWidth) 
 
     .attr("height", divHeight) 
 
     .call(d3.behavior.zoom().on("zoom", function() { 
 
     svg.attr("transform", "translate(" + d3.event.translate[0] + "," + d3.event.translate[1] + ")" + " scale(" + d3.event.scale + ")") 
 
     })).on("dblclick.zoom", null) 
 
     .append("g") 
 
     .attr("transform", "translate(" + divWidth/2 + "," + divHeight/2 + ")") 
 
     .append("g"); 
 

 
    //alert("W = " + divWidth + ", H = " + divHeight); 
 

 
    root = flare; 
 
    root.x0 = height/2; 
 
    root.y0 = 0; 
 

 
    root.children.forEach(collapse); // start with all children collapsed 
 
    update(root); 
 

 
    //create a circle in the center to remove root and first level of links 
 
    var circle = svg.append("circle") 
 
     .attr("cx", 0) 
 
     .attr("cy", 0) 
 
     .attr("r", radius - 5) 
 
     .style("fill", "white"); 
 

 
    d3.select(self.frameElement).style("height", "800px"); 
 

 
    function update(source) { 
 

 
     // Compute the new tree layout. 
 
     var nodes = tree.nodes(root), 
 
     links = tree.links(nodes); 
 

 
     // Normalize for fixed-depth. 
 
     nodes.forEach(function(d) { 
 
     d.y = d.depth * radius; 
 
     }); 
 

 
     // Update the nodes… 
 
     var node = svg.selectAll("g.node") 
 
     .data(nodes, function(d) { 
 
      return d.id || (d.id = ++i); 
 
     }); 
 

 
     // Enter any new nodes at the parent's previous position. 
 
     var nodeEnter = node.enter().append("g") 
 
     .attr("class", "node") 
 
     //.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; }) 
 
     .on("click", click); 
 

 
     nodeEnter.append("circle") 
 
     .attr("r", 1e-6) 
 
     .style("fill", function(d) { 
 
      return d._children ? "lightsteelblue" : "#fff"; 
 
     }); 
 

 
     nodeEnter.append("text") 
 
     .attr("x", 10) 
 
     .attr("dy", ".35em") 
 
     .attr("text-anchor", "start") 
 
     //.attr("transform", function(d) { return d.x < 180 ? "translate(0)" : "rotate(180)translate(-" + (d.name.length * 8.5) + ")"; }) 
 
     .text(function(d) { 
 
      return d.name; 
 
     }) 
 
     .style("fill-opacity", 1e-6); 
 

 
     // Transition nodes to their new position. 
 
     var nodeUpdate = node.transition() 
 
     .duration(duration) 
 
     .attr("transform", function(d) { 
 
      return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; 
 
     }) 
 

 
     nodeUpdate.select("circle") 
 
     .attr("r", 4.5) 
 
     .style("fill", function(d) { 
 
      return d._children ? "lightsteelblue" : "#fff"; 
 
     }); 
 

 
     nodeUpdate.select("text") 
 
     .style("fill-opacity", 1) 
 
     .attr("transform", function(d) { 
 
      return d.x < 180 ? "translate(0)" : "rotate(180)translate(-" + (d.name.length + 50) + ")"; 
 
     }); 
 

 
     // TODO: appropriate transform 
 
     var nodeExit = node.exit().transition() 
 
     .duration(duration) 
 
     //.attr("transform", function(d) { return "diagonal(" + source.y + "," + source.x + ")"; }) 
 
     .remove(); 
 

 
     nodeExit.select("circle") 
 
     .attr("r", 1e-6); 
 

 
     nodeExit.select("text") 
 
     .style("fill-opacity", 1e-6); 
 

 
     // Update the links… 
 
     var link = svg.selectAll("path.link") 
 
     .data(links, function(d) { 
 
      return d.target.id; 
 
     }); 
 

 
     // Enter any new links at the parent's previous position. 
 
     link.enter().insert("path", "g") 
 
     .attr("class", "link") 
 
     .attr("d", function(d) { 
 
      var o = { 
 
      x: source.x0, 
 
      y: source.y0 
 
      }; 
 
      return diagonal({ 
 
      source: o, 
 
      target: o 
 
      }); 
 
     }); 
 

 
     // Transition links to their new position. 
 
     var arc = d3.svg.arc(); 
 

 
     link.transition() 
 
     .duration(duration) 
 
     .attr("d", function(d) { 
 

 
      if (d.source.depth === 0) return ""; 
 
      
 
      if (d.source.children) { 
 
      
 
      if (d.source.children[0] !== d.target && 
 
       d.source.children[d.source.children.length - 1] !== d.target) 
 
       return "" 
 
      
 
      var pad = 10, 
 
       sum = 0; 
 
      d.source.children.forEach(function(c) { 
 
       sum += c.x; 
 
      }); 
 

 
      // this is the mid point position 
 
      var ma1 = ((sum/d.source.children.length) - 90) * (Math.PI/180), 
 
       ma2 = ((sum/d.source.children.length)) * (Math.PI/180), 
 
       mr = d.source.children[0].y - pad, 
 
       mid = [mr * Math.cos(ma1), mr * Math.sin(ma1)]; 
 

 
      // this is the source position 
 
      var sa = (d.source.x - 90) * (Math.PI/180), 
 
       sr = d.source.y - pad, 
 
       source = [sr * Math.cos(sa), sr * Math.sin(sa)]; 
 

 
      // this is the final target position 
 
      var ta = (d.target.x) * (Math.PI/180), 
 
       tr = d.target.y - pad, 
 
       target = [tr * Math.cos(ta), tr * Math.sin(ta)]; 
 

 
      // this is the arc from mid to target 
 
      var dx = target[0] - source[0], 
 
       dy = target[1] - source[1], 
 
       dr = Math.sqrt(dx * dx + dy * dy); 
 
       
 
      arc.innerRadius(tr-1) 
 
       .outerRadius(tr) 
 
       .startAngle(ma2) 
 
       .endAngle(ta); 
 
       
 
      console.log(arc()) 
 
      
 
      return "M" + source + "L" + mid + arc(); 
 

 
      /* return "M" + source + 
 
       "L" + mid + 
 
       "A" + dr + "," + dr + " 0 0," + (ma < ta ? 1 : 0) + " " + target[0] + "," + target[1]; 
 
      */ 
 
      } 
 
     }); 
 

 
     // Transition exiting nodes to the parent's new position. 
 
     link.exit().transition() 
 
     .duration(duration) 
 
     .attr("d", function(d) { 
 
      var o = { 
 
      x: source.x, 
 
      y: source.y 
 
      }; 
 
      return diagonal({ 
 
      source: o, 
 
      target: o 
 
      }); 
 
     }) 
 
     .remove(); 
 

 
     // Stash the old positions for transition. 
 
     nodes.forEach(function(d) { 
 
     d.x0 = d.x; 
 
     d.y0 = d.y; 
 
     }); 
 
    } 
 

 
    // Toggle children on click. 
 
    function click(d) { 
 
     if (d.children) { 
 
     d._children = d.children; 
 
     d.children = null; 
 
     } else { 
 
     d.children = d._children; 
 
     d._children = null; 
 
     } 
 

 
     update(d); 
 
    } 
 

 
    // Collapse nodes 
 
    function collapse(d) { 
 
     if (d.children) { 
 
     d._children = d.children; 
 
     d._children.forEach(collapse); 
 
     d.children = null; 
 
     } 
 
    } 
 
    </script> 
 
</body> 
 

 
</html>

Plunker版本here

+0

这是一个非常好的开始!然而,弧线都有自己的路径,当你使用大量数据时,它们看起来并不像它们在同一弧线上(http://i.imgur.com/GxnmWsZ.png)。可能解决这个问题的方法是,不会从线条末端绘制弧线,而是始终绘制连接到每个儿童的相同外部圆,以便只改变大小,而不是半径或中心。我会尽力建立在这个基础上,但随时更新它,我会接受你的答案。 – MorganFR

+0

也许进一步提高中点位置(找到合适的位置)可以解决问题吗?我的数学非常糟糕,所以我目前正试图弄清楚如何移动中点,以及弧的起点。 – MorganFR

+1

@MorganFR,检查上面的更新。修复您提出的问题。这是一个更好的实现。 – Mark

相关问题