Advertisement
attilan

Round SVG range slider with D3

Apr 18th, 2019
284
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // base variables
  2. var width = 500;
  3. var height = 500;
  4. var arcInnerRadius = 180;
  5. var arcOuterRadius = 200;
  6. var arcStartAngle = 180;
  7. var arcEndAngle = 360;
  8. var sliderCircleRadius = 16;
  9. var sliderRadius = 190; //
  10. var yAxisOffset = 120; // 0: a half circle. 120: 120px 'longer' then a half circle
  11.  
  12. var svg = d3
  13.   .select("body")
  14.   .append("svg")
  15.   .attr("width", width)
  16.   .attr("height", height)
  17.   .append("g")
  18.   .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); // move the arc to the center of its container
  19.  
  20. var arc = d3
  21.   .arc()
  22.   .innerRadius(arcInnerRadius)
  23.   .outerRadius(arcOuterRadius)
  24.   .startAngle(degToRad(arcStartAngle))
  25.   .endAngle(degToRad(arcEndAngle));
  26.  
  27. svg.on("touchstart", function(d) {}).on("touchmove", function(d) {}); // for touch devices
  28.  
  29. var def = svg.append("defs");
  30. var gradient = def
  31.   .append("linearGradient")
  32.   .attr("id", "gradientDef")
  33.   .attr("x1", "0%")
  34.   .attr("y1", "0%")
  35.   .attr("x2", "0%")
  36.   .attr("y2", "100%");
  37. gradient
  38.   .append("stop")
  39.   .attr("offset", "0%")
  40.   .attr("style", "stop-color: #f7be56; stop-opacity:1");
  41. gradient
  42.   .append("stop")
  43.   .attr("offset", "50%")
  44.   .attr("style", "stop-color: #89fe40; stop-opacity:1");
  45. gradient
  46.   .append("stop")
  47.   .attr("offset", "100%")
  48.   .attr("style", "stop-color: #2ac8fc; stop-opacity:1");
  49.  
  50. var drag = d3
  51.   .drag()
  52.   .on("start", dragstarted)
  53.   .on("drag", dragged)
  54.   .on("end", dragended);
  55.  
  56. function dragstarted(d) {
  57.   d3.event.sourceEvent.stopPropagation();
  58.   d3.select(this).classed("dragging", true);
  59. }
  60.  
  61. var handle = [
  62.   {
  63.     x: -calcStarterPointX(),
  64.     y: yAxisOffset
  65.   }
  66. ];
  67.  
  68. var dot = svg.append("g").attr("class", "dot");
  69.  
  70. function dragged(d) {
  71.   if (d.y <= yAxisOffset) {
  72.     var c = Math.sqrt(Math.pow(d3.event.x, 2) + Math.pow(d3.event.y, 2));
  73.     var a = Math.acos(d3.event.x / c);
  74.  
  75.     d3.select(this) // this = circle
  76.       .attr("cx", function() {
  77.         var value = sliderRadius * Math.cos(a);
  78.         return (d.x = d.y < yAxisOffset ? (d.x = value) : d.x);
  79.       })
  80.       .attr("cy", function() {
  81.         var value =
  82.           d3.event.y < 0
  83.             ? -sliderRadius * Math.sin(a)
  84.             : sliderRadius * Math.sin(a);
  85.         return (d.y = value <= yAxisOffset ? value : yAxisOffset);
  86.       });
  87.  
  88.     // sides
  89.     var sideA = sliderRadius;
  90.     var sideB = Math.sqrt(Math.pow(d.x, 2) + Math.pow(d.y, 2));
  91.     var sideC = Math.sqrt(Math.pow(d.x, 2) + Math.pow(sliderRadius - d.y, 2));
  92.  
  93.     var alpha = calcDegreeLawOfCosines(sideA, sideB, sideC);
  94.  
  95.     if (d3.event.x >= 0 && d3.event.x <= sliderRadius) {
  96.       drawNewArc(-(alpha - 180) + 90);
  97.     } else if (d3.event.x >= -sliderRadius && d3.event.x < 0) {
  98.       drawNewArc(alpha - 90);
  99.     }
  100.     drawCircle();
  101.   }
  102. }
  103.  
  104. function dragended(d) {
  105.   d3.select(this).classed("dragging", false);
  106. }
  107.  
  108. drawCircle();
  109.  
  110. function drawNewArc(value) {
  111.   d3.selectAll("#baseArc").remove();
  112.   var startAngle =
  113.     yAxisOffset > 0
  114.       ? degToRad(
  115.           180 -
  116.             (90 -
  117.               calcDegreeLawOfCosines(
  118.                 yAxisOffset,
  119.                 sliderRadius,
  120.                 calcStarterPointX()
  121.               ))
  122.         )
  123.       : 180;
  124.   var newArc = d3
  125.     .arc()
  126.     .innerRadius(arcInnerRadius)
  127.     .outerRadius(arcOuterRadius)
  128.     .startAngle(startAngle)
  129.     .endAngle(degToRad(value + 180));
  130.   dot
  131.     .append("path")
  132.     .attr("d", newArc)
  133.     .attr("id", "baseArc")
  134.     .attr("fill", "url(#gradientDef")
  135.     .attr("transform", "rotate(90)")
  136.     .classed("arc", true);
  137. }
  138.  
  139. function drawCircle() {
  140.   d3.selectAll(".toggle-circle").remove();
  141.   dot
  142.     .selectAll("circle")
  143.     .data(handle)
  144.     .enter()
  145.     .append("circle")
  146.     .attr("r", sliderCircleRadius)
  147.     // .attr("cx", 480)
  148.     // .attr("cy", 250)
  149.     .attr("cx", function(d) {
  150.       return d.x;
  151.     })
  152.     .attr("cy", function(d) {
  153.       return d.y;
  154.     })
  155.     .classed("toggle-circle", true)
  156.     .call(drag);
  157. }
  158.  
  159. // helper functions
  160. function degToRad(degree) {
  161.   return (degree * Math.PI) / 180;
  162. }
  163.  
  164. function radToDeg(radian) {
  165.   return (180 / Math.PI) * radian;
  166. }
  167.  
  168. function calcStarterPointX() {
  169.   // Pythagorean theorem
  170.   return Math.sqrt(Math.pow(sliderRadius, 2) - Math.pow(yAxisOffset, 2));
  171. }
  172.  
  173. function calcDegreeLawOfCosines(sideA, sideB, sideC) {
  174.   return radToDeg(
  175.     Math.acos(
  176.       (Math.pow(sideC, 2) - Math.pow(sideA, 2) - Math.pow(sideB, 2)) /
  177.         (-2 * sideA * sideB)
  178.     )
  179.   );
  180. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement