block by HarryStevens d1bc769436b43438d9b02d25a3315e0d

Range Slider

Full Screen

Use d3-selection, d3-scale, d3-drag, d3-axis and d3-marcon to make a range slider.

index.html

<!DOCTYPE html>
<html>
<head>
	<style>
	body {
		margin: 0;
		font-family: "Helvetica Neue", sans-serif;
	}
	.range-body {
		fill: #666;
	}
	.range-dragger {
		fill: tomato;
		cursor: pointer;
	}
	.range-label {
		fill: #fff;
		text-anchor: middle;
		font-size: 2em;
		pointer-events: none;
	}
	.range-axis line, .range-axis path {
		stroke: #666;
	}
	.range-axis text {
		fill: #666;
	}
	</style>
</head>
<body>
	<div id="range"></div>
	<script src="https://d3js.org/d3.v4.min.js"></script>
	<script src="https://unpkg.com/d3-marcon@2.0.2/build/d3-marcon.min.js"></script>
	<script>
		var handle_radius = 50,
			handle_start_val = 50,
			handle_padding = 10,
			slider_height = 5,
			axis_height = 20;

		var setup = d3.marcon()
				.width(window.innerWidth)
				.height(handle_radius * 2 + slider_height + handle_padding + axis_height)
				.left(handle_radius)
				.right(handle_radius)
				.bottom(axis_height)
				.element("#range");

		setup.render();

		var range_width = setup.innerWidth(), range_height = setup.innerHeight(), range_svg = setup.svg();

		var range_x = d3.scaleLinear()
				.range([0, range_width])
				.domain([0, 100]);

		// the range axis
		range_svg.append("g")
				.attr("class", "range-axis")
				.attr("transform", "translate(0, " + range_height + ")")
				.call(d3.axisBottom(range_x))

		// the range scale
		range_svg.append("rect")
				.attr("class", "range-body")
				.attr("x", 0)
				.attr("y", range_height - slider_height)
				.attr("width", range_width)
				.attr("height", slider_height);

		// the handle
		range_svg.append("circle")
				.attr("class", "range-dragger range-handle")
				.attr("cx", range_x(handle_start_val))
				.attr("cy", range_height - slider_height - handle_radius - handle_padding)
				.attr("r", handle_radius)
				.call(d3.drag()
					.on("drag", dragged)
				);

		// the label
		range_svg.append("text")
				.attr("class", "range-label")
				.attr("x", range_x(handle_start_val))
				.attr("y", range_height - slider_height - handle_radius - handle_padding)
				.attr("dy", ".3em")
				.text(handle_start_val);

		// the pointer
		range_svg.append("polygon")
				.attr("class", "range-dragger range-pointer")
				.attr("points", calcPointerPoints(handle_start_val))
				.call(d3.drag()
					.on("drag", dragged)
				);

		function calcPointerPoints(handle_val){
			var point_c = range_x(handle_val) + "," + (range_height - slider_height);
			var point_a = (range_x(handle_val) - (handle_radius / 4)) + "," + (range_height - slider_height - handle_padding - (handle_radius / 10));
			var point_b = (range_x(handle_val) + (handle_radius / 4)) + "," + (range_height - slider_height - handle_padding - (handle_radius / 10));
			return point_a + " " + point_b + " " + point_c;
		}

		function dragged(){

			var coordinates = [0, 0];
      coordinates = d3.mouse(this);
      var x = coordinates[0];
      x = x > range_width ? range_width :
      	x < 0 ? 0 :
      	x;

      // find the pct represented by the mouse position
      var pct = Math.round(range_x.invert(x));
      
      range_svg.select(".range-handle")
      		.attr("cx", range_x(pct));

      range_svg.select(".range-label")
      		.attr("x", range_x(pct))
      		.text(pct);

      range_svg.select(".range-pointer")
      		.attr("points", calcPointerPoints(pct));

		}

	</script>

</body>
</html>