Saurabh Sinha
Saurabh Sinha

Reputation: 1800

add circle in a spiral chart with d3js with line connecting to center

enter image description herehi I created a spiral chart in d3.js, and I want to add circle to different position of the spiral lines.according to there values. circle closes to the center will have highest priority. any idea how to do that.

here is the code which i wrote

var width = 400,
height = 430
num_axes = 8,
tick_axis = 1,
start = 0
end = 4;

var theta = function(r) {
  return -2*Math.PI*r;
};

var arc = d3.svg.arc()
  .startAngle(0)
  .endAngle(2*Math.PI);

var radius = d3.scale.linear()
  .domain([start, end])
  .range([0, d3.min([width,height])/2-20]);

var angle = d3.scale.linear()
  .domain([0,num_axes])
  .range([0,360])

var svg = d3.select("#chart").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width/2 + "," + (height/2+8) +")");

var pieces = d3.range(start, end+0.001, (end-start)/1000);

var spiral = d3.svg.line.radial()
  .interpolate("cardinal")
  .angle(theta)
  .radius(radius);

//svg.append("text")
//  .text("And there was much rejoicing!")
//  .attr("class", "title")
//  .attr("x", 0)
//  .attr("y", -height/2+16)
//  .attr("text-anchor", "middle")

//svg.selectAll("circle.tick")
//    .data(d3.range(end,start,(start-end)/4))
//  .enter().append("circle")
//    .attr("class", "tick")
//    .attr("cx", 0)
//    .attr("cy", 0)
//    .attr("r", function(d) { return radius(d); })

svg.selectAll(".axis")
    .data(d3.range(num_axes))
  .enter().append("g")
    .attr("class", "axis")
    .attr("transform", function(d) { return "rotate(" + -angle(d) + ")"; })
  .call(radial_tick)
  .append("text")
    .attr("y", radius(end)+13)
    .text(function(d) { return angle(d) + "°"; })
    .attr("text-anchor", "middle")
    .attr("transform", function(d) { return "rotate(" + -90 + ")" })

svg.selectAll(".spiral")
    .data([pieces])
  .enter().append("path")
    .attr("class", "spiral")
    .attr("d", spiral)
    .attr("transform", function(d) { return "rotate(" + 90 + ")" });

function radial_tick(selection) {
  selection.each(function(axis_num) {
    d3.svg.axis()
      .scale(radius)
      .ticks(5)
      .tickValues( axis_num == tick_axis ? null : [])
      .orient("bottom")(d3.select(this))

    d3.select(this)
      .selectAll("text")
      .attr("text-anchor", "bottom")
      .attr("transform", "rotate(" + angle(axis_num) + ")")
  });
}

enter image description here please see the second solution for my implementation. Help me with connecting the circle with the center

Upvotes: 3

Views: 2126

Answers (1)

Cool Blue
Cool Blue

Reputation: 6476

Here is a model for the technique you seem to be looking for...

var width = 400,
		height = 430,
		num_axes = 8,
		tick_axis = 1,
		start = 0,
		end = 4,
		testValue = 2;

		var theta = function (r) {
			return -2 * Math.PI * r;
		};

		var arc = d3.svg.arc()
			.startAngle(0)
			.endAngle(2 * Math.PI);

		var radius = d3.scale.linear()
			.domain([start, end])
			.range([0, (d3.min([width, height]) / 2 - 20)]);

		var angle = d3.scale.linear()
			.domain([0, num_axes])
			.range([0, 360]);

		var chart = d3.select("#chart")
			.style("width", width + "px");

		var svg = d3.select("#chart").append("svg")
				.attr("width", width)
				.attr("height", height)
			.append("g")
				.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 8) + ")");

		var pieces = d3.range(start, end + 0.001, (end - start) / 500);

		var spiral = d3.svg.line.radial()
			.interpolate("linear")
			.angle(theta)
			.radius(radius);
		
		svg.append("text")
			.text("Title")
			.attr("class", "title")
			.attr("x", 0)
			.attr("y", -height/2+16)
			.attr("text-anchor", "middle")

		svg.selectAll("circle.tick")
				.data(d3.range(end,start,(start-end)/4))
			.enter().append("circle")
				.attr("class", "tick")
				.style({fill: "black", opacity: 0.1})
				.attr("cx", 0)
				.attr("cy", 0)
				.attr("r", function(d) { return radius(d); })

		svg.selectAll(".axis")
				.data(d3.range(num_axes))
			.enter().append("g")
				.attr("class", "axis")
				.attr("transform", function (d) { return "rotate(" + -angle(d) + ")"; })
			.call(radial_tick)
			.append("text")
				.attr("y", radius(end) + 13)
				.text(function (d) { return angle(d) + "°"; })
				.attr("text-anchor", "middle")
				.attr("transform", function (d) { return "rotate(" + -90 + ")" })

		svg.selectAll(".axis path")
			.style({fill: "none", stroke: "black"})
			.attr("stroke-dasharray", "5 5")

		svg.selectAll(".spiral")
				.data([pieces])
			.enter().append("path")
				.attr("class", "spiral")
				.attr("fill", "none")
				.attr("stroke", "black")
				.attr("d", spiral)
				.attr("transform", function (d) { return "rotate(" + 90 + ")" });

		function radial_tick(selection) {
			selection.each(function (axis_num) {
				d3.svg.axis()
					.scale(radius)
					.ticks(5)
					.tickValues(axis_num == tick_axis ? null : [])
					.tickSize(1)
					.orient("bottom")(d3.select(this))

				d3.select(this)
					.selectAll("text")
					.attr("text-anchor", "bottom")
					.attr("transform", "rotate(" + angle(axis_num) + ")")
			});
		}
		function radialScale(x) {
			var t = theta(x), r = radius(x);
			d3.select(this)
			.attr("cx", r * Math.cos(t))
			.attr("cy", r * Math.sin(t))
		}

		slider = SliderControl("#circleSlider", "data", update, [start, end], ",.3f");

		function update(x) {

		  if (typeof x != "undefined") testValue = x;
			
			var circles = svg.selectAll(".dataPoints")
				.data([testValue]);
			circles.enter().append("circle");

		  circles.attr("class", "dataPoints")
					.style({ fill: "black", opacity: 0.6 })
					.attr("r", 10)
					.each(radialScale)
			circles.exit().remove();
			return testValue
		}

		function SliderControl(selector, title, value, domain, format) {
			var accessor = d3.functor(value), rangeMax = 1000,
					_scale = d3.scale.linear().domain(domain).range([0, rangeMax]),
					_$outputDiv = $("<div />", { class: "slider-value" }),
					_update = function (value) {
						_$outputDiv.css("left", 'calc( '
							+ (_$slider.position().left + _$slider.outerWidth()) + 'px + 1em )')
						_$outputDiv.text(d3.format(format)(value));
						$(".input").width(_$outputDiv.position().left + _$outputDiv.outerWidth() - _innerLeft)

					},

					_$slider = $(selector).slider({
						value: _scale(accessor()),
						max: rangeMax,
						slide: function (e, ui) {
							_update(_scale.invert(ui.value));
							accessor(_scale.invert(ui.value));
						}
					}),
					_$wrapper = _$slider.wrap("<div class='input'></div>")
					.before($("<div />").text(title + ":"))
					.after(_$outputDiv).parent(),
					_innerLeft = _$wrapper.children().first().position().left;

			_update(_scale.invert($(selector).slider("value")))

			return d3.select(selector)
		};
.domain {
			stroke-width: 1px;
		}
<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
	<div id="chart">
		<div id="circleSlider"></div>
	</div>

Upvotes: 1

Related Questions