Code & result is here: https://jsfiddle.net/nohjose/fdarxu7j/3/#&togetherjs=HpJOmlQkpI
I have coded a d3 (or at least d3 like) radial line graph to show solar panel generation rates over the last four years. I want to have a single line per year (different colour per year) outside the base circle and with a maximum set by a control (which varies the value of the variable 'amplitude'). I have data for every 10mins providing the panels didn't generate 0 Watts but for this graph plan to average the data for each day. I have a php file that returns JSON data in this form
["2014-01-01 09:00:00","0.018"]["2014-01-01 09:00:00","0.018"]["2014-01-01 09:00:00","0.018"]["2014-01-01 09:00:00","0.018"]...
I don't see how I'd now plot the data on my graph?
I know this may not be specific enough for StackOverflow but I'm stuck at the point before where I have a specific technical issue and I'm not sure where else to turn. Kindness appreciated :o)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Solar Generation Visualisation</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<link href='http://fonts.googleapis.com/css?family=Lato&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
<style>
.xAxis {
fill: yellow;
stroke: orange;
stroke-width: 3px;
}
.xBigTick {
fill: none;
stroke: red;
stroke-width: 1px;
}
.xSmallTick {
fill: none;
stroke: #303030;
stroke-width: 0.25px;
}
.axisText {
font-family: Lato;
font-weight: 300;
font-size: 8pt;
}
.button {
fill: silver;
stroke: gray;
stroke-width: 3px;
}
</style>
</head>
<body>
<script type="text/javascript">
// Get the data
var data;
d3.json("./test.php", function(error, json) {
if (error) return console.warn(error);
data = json;
data.forEach(function(d) {
d.Timestamp = parseDate(d.Timestamp);
d.Power = +d.Power;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.Timestamp; }));
y.domain([0, d3.max(data, function(d) { return d.Power; })]);
});
</script>
<script type="text/javascript">
var canvasWidth= 1000;
var canvasHeight= 500;
var originx = canvasWidth/2;
var originy = canvasHeight/2;
var pi = Math.PI;
var DRratio = pi/180;
var degPerDay = 360/365;
var radPerDay = degPerDay*DRratio;
var bigTick = 100;
var smallTick = 20;
var baseRad = canvasHeight/2-bigTick;
//var baseRad = 200;
var amplitude = 1; //for magnifying the y axis data
var textMargin = 25;
var textMargin180 = 11;
var angleAdjust = 1.5*DRratio;
var angleAdjust180 = 5*DRratio;
var monthAngleAdjust = -18*DRratio;
var week = 0;
// Canvas
var svg = d3.select("body")
.append("svg")
.attr("width", canvasWidth)
.attr("height", canvasHeight);
// x axis line (radial version)
var circle = d3.select("svg")
.append("circle")
.attr("cx", originx)
.attr("cy", originy)
.attr("r", baseRad)
.attr("class", "xAxis");
// weekly (big) tick marks
for (a=0; a<=2*pi; a+=(radPerDay)*7) {
var line = d3.select("svg")
.append("line")
.attr("x1", originx + (baseRad * Math.cos(a)))
.attr("y1", originy + (baseRad * Math.sin(a)))
.attr("x2", originx + ((baseRad + bigTick) * Math.cos(a)))
.attr("y2", originy + ((baseRad + bigTick) * Math.sin(a)))
.attr("class", "xBigTick");
};
// axis labels
for (a=0; a<=2*pi; a+=(radPerDay)*7) {
var group = d3.select("svg")
.append("g")
//console.log('week-' + week + ' angle:' + a/DRratio + 'degrees'+ ' cos:' + Math.cos(a)+ ' Sin:' + Math.sin(a));
var text = d3.select("g")
.append("text")
.attr("class", "axisText")
.attr("style", "fill:black")
.attr("opacity", "1")
.text(week);
// adjust the label orientation & tweak the position
if (a > 0 && (a < (pi/2))){
text.attr("transform", "translate(" + (originx + (baseRad - textMargin) * Math.cos( -a+angleAdjust )) + "," + (originy - (baseRad - textMargin) * Math.sin( -a+angleAdjust )) + ")rotate(" + (a/DRratio) +")");
}
if ((a > (pi/2)) && (a < (3*pi/2))){
text.attr("transform", "translate(" + (originx + (baseRad - textMargin180) * Math.cos( -a+angleAdjust180 )) + "," + (originy - (baseRad - textMargin180) * Math.sin( -a+angleAdjust180 )) + ")rotate(" + (a/DRratio+180) +")");
}
if ((a > (3*pi/2)) && (a < (2*pi))){
text.attr("transform", "translate(" + (originx + (baseRad - textMargin) * Math.cos( -a+angleAdjust )) + "," + (originy - (baseRad - textMargin) * Math.sin( -a+angleAdjust )) + ")rotate(" + (a/DRratio) +")");
}
week=week+1;
};
// weekly (big) tick marks
for (a=0; a<=2*pi; a+=(radPerDay)*7) {
var line = d3.select("svg")
.append("line")
.attr("x1", originx + (baseRad * Math.cos(a)))
.attr("y1", originy + (baseRad * Math.sin(a)))
.attr("x2", originx + ((baseRad + bigTick) * Math.cos(a)))
.attr("y2", originy + ((baseRad + bigTick) * Math.sin(a)))
.attr("class", "xBigTick");
};
// month labels
var inrad = 100;
var outrad = baseRad - textMargin;
var months= [31,28,31,30,31,30,31,31,30,31,30,31];
var month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var mr = 0;
// monthly (inner) lead lines
for (a=0; a<=11; a+=1) {
var line = d3.select("svg")
.append("line")
.attr("x1", originx + (inrad * Math.cos(mr)))
.attr("y1", originy + (inrad * Math.sin(mr)))
.attr("x2", originx + (outrad * Math.cos(mr)))
.attr("y2", originy + (outrad * Math.sin(mr)))
.attr("class", "xBigTick");
mr = mr + months[a]*radPerDay;
//console.log('cumulative day at end of month: ' + m + '(' + (m * radPerDay) + ')');
};
md = 0;
mr = 0;
//month text
for (a=0; a<=11; a+=1) {
var group = d3.select("svg")
.append("g")
//console.log('week-' + week + ' angle:' + a/DRratio + 'degrees'+ ' cos:' + Math.cos(a)+ ' Sin:' + Math.sin(a));
var text = d3.select("g")
.append("text")
.attr("class", "axisText")
.attr("style", "fill:black")
.attr("opacity", "1")
.text(month[a]);
// adjust the month label orientation & tweak the position
if (md >= 0 && (md < 90)){
text.attr("transform", "translate(" + (originx + ((inrad - textMargin) * Math.cos( -mr+monthAngleAdjust ))) + "," + (originy - ((inrad - textMargin) * Math.sin( -mr+monthAngleAdjust ))) + ")rotate(" + (md) +")");
}
if ((md > 90) && (md < 270)){
text.attr("transform", "translate(" + (originx + (inrad ) * Math.cos( -mr+monthAngleAdjust )) + "," + (originy - (inrad) * Math.sin( -mr+monthAngleAdjust )) + ")rotate(" + (md+180) +")");
}
if ((md >270) && (md < 360)){
text.attr("transform", "translate(" + (originx + (inrad - textMargin) * Math.cos( -mr+monthAngleAdjust )) + "," + (originy - (inrad - textMargin) * Math.sin( -mr+monthAngleAdjust )) + ")rotate(" + (md) +")");
}
md = md + months[a]*degPerDay;
mr = mr + months[a]*radPerDay;
//console.log(md + "deg = " + mr + "rad");
};
// daily (small) tick marks
for (a=0; a<=2*pi; a+=(radPerDay)) {
var line = d3.select("svg")
.append("line")
.attr("x1", originx + (baseRad * Math.cos(a)))
.attr("y1", originy + (baseRad * Math.sin(a)))
.attr("x2", originx + ((baseRad + smallTick) * Math.cos(a)))
.attr("y2", originy + ((baseRad + smallTick) * Math.sin(a)))
.attr("class", "xSmallTick");
};
//control handle (move to adjust amplitude)
var circle = d3.select("svg")
.append("circle")
.attr("cx", originx)
.attr("cy", originy)
.attr("r", 10)
.attr("class", "button");
</script>
</body>
</html>
Related
I'm new in d3.js graph. I have developed a d3 Gauge Chart with version 5.16.0. But I need to add inner grey dotted line as shown in the attached image. I have attached the image. Can you help me to achieve that inner grey dotted line?
My .cshtml file:
Script version 5.16.0
<div id="OverviewChart"></div>
My css file:
.chart-gauge {
}
.chart-first {
fill: #1A9AD4
}
.chart-second {
fill: #10B981
}
.chart-third {
fill: #F59E0B
}
.chart-fourth {
fill: #EF4444
}
.needle, .needle-center {
fill: #464A4F
}
My Js file:
var width = 288;
var height = 288;
var radius = Math.min(width, height) / 2;
var chartInset = 10;
var barWidth = 20;
var innerRadius = radius - chartInset - barWidth;
var outerRadius = radius - chartInset;
var color = "#66AB8C";
var totalPercent = .75;
var padRad = 0.025;
//****Utility methods****
var percToRad = function (perc) {
return degToRad(percToDeg(perc));
};
var degToRad = function (deg) {
return deg * Math.PI / 180;
};
var percToDeg = function (perc) {
return perc * 360;
};
var margin = {
top: 20,
right: 20,
bottom: 20,
left: 20
};
//****Set up the SVG container****
const svg = d3.select("#OverviewChart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height / 1.5 + margin.top + margin.bottom);
// Add layer for the panel
chart = svg.append('g').attr('transform', "translate(" + ((width + margin.left) / 2) + ", " + ((height + margin.top) / 2) + ")");
chart.append('path').attr('class', "arc chart-first");
chart.append('path').attr('class', "arc chart-second");
chart.append('path').attr('class', "arc chart-third");
chart.append('path').attr('class', "arc chart-fourth");
//****Set up the scales****
const scale = d3.scaleLinear()
.domain([0, 100]) // The range of possible values
.range([0, 2 * Math.PI]); // The range of angles in radians
//****Set up the arc generator*****
perc = 0.5;
perc1 = 0.25;
perc2 = 0.25;
perc3 = 0.5;
var next_start = totalPercent;
arcStartRad = percToRad(next_start);
arcEndRad = arcStartRad + percToRad(perc / 3);
next_start += perc / 3;
const arc1 = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius).startAngle(arcStartRad).endAngle(arcEndRad);
arcStartRad = percToRad(next_start);
arcEndRad = arcStartRad + percToRad(perc1 / 3);
next_start += perc1 / 3;
const arc2 = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius).startAngle(arcStartRad + padRad).endAngle(arcEndRad);
arcStartRad = percToRad(next_start);
arcEndRad = arcStartRad + percToRad(perc2 / 3);
next_start += perc2 / 3;
const arc3 = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius).startAngle(arcStartRad + padRad).endAngle(arcEndRad);
arcStartRad = percToRad(next_start);
arcEndRad = arcStartRad + percToRad(perc3 / 3);
const arc4 = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius).startAngle(arcStartRad + padRad).endAngle(arcEndRad);
////****Add the gauge to the SVG****
chart.select(".chart-first").attr('d', arc1);
chart.select(".chart-second").attr('d', arc2);
chart.select(".chart-third").attr('d', arc3);
chart.select(".chart-fourth").attr('d', arc4);
//svg.append("path")
// .attr('class', 'arc chart-first')
// .attr("d", arc1)
// .style("fill", color);
//****Add the value text to the center of the gauge****
//svg.append("text")
// .attr("x", width / 2)
// .attr("y", height / 2)
// .text("Hi")
// .style("text-anchor", "middle")
// .style("font-size", "24px");
var dataset = [{
metric: "Overall Task",//name,
//value: value
}]
var texts = svg.selectAll("text")
.data(dataset)
.enter();
texts.append("text")
.text(function () {
return "388";
})
.attr('id', "Name")
.attr('transform', "translate(" + ((width + margin.left) / 2.3) + ", " + ((height + margin.top) / 2.5) + ")")
.attr("font-family", "Open Sans")
.attr("font-size", 28)
.attr("font-weight", 600)
.attr("line-height", 34)
.attr("letter-spacing", -0.02)
.attr("text-align", "center")
.style("fill", "#000000");
texts.append("text")
.text(function () {
return dataset[0].metric;
})
.attr('id', "Name")
.attr('transform', "translate(" + ((width + margin.left) / 3) + ", " + ((height + margin.top) / 1.5) + ")")
.attr("font-family", "Open Sans")
.attr("font-size", 18)
.attr("font-weight", 600)
.attr("line-height", 22)
.attr("letter-spacing", 0)
.attr("text-align", "left")
.style("fill", "#000000");
texts.append("text")
.text(function () {
return "Updated on 07/11/2022";
})
.attr('id', "Name")
.attr('transform', "translate(" + ((width + margin.left) / 3.5) + ", " + ((height + margin.top) / 1.37) + ")")
.attr("font-family", "Open Sans")
.attr("font-size", 12)
.attr("font-weight", 400)
.attr("line-height", 18)
.attr("letter-spacing", 0)
.attr("text-align", "left")
.style("fill", "#000000");
I have a d3 radial chart created using some community sample and stack-overflow posts.
Here the two bottom labels and numbers are in mirrored form (A13 and A14). Looking for some snippets to transform only this two in counter-clockwise with numbers top (next to the chart) then label so that it will be in better readable form.
JSFiddle
var data = [
{"name":"A11","value":217,"color":"#fad64b"},
{"name":"A12","value":86,"color":"#f15d5d"},
{"name":"A13","value":79,"color":"#f15d5d"},
{"name":"A14","value":82,"color":"#f15d5d"},
{"name":"A15","value":101,"color":"#fad64b"},
{"name":"A16","value":91,"color":"#fad64b"}
];
var width = 500;
var height = 300;
var barHeight = height / 2 - 15;
var formatNumber = d3.format('s');
var color = d3.scale.ordinal()
.range(['#F15D5D', '#FAD64B']);
var svg = d3.select('#chart').append('svg')
.attr('width', width)
.attr('height', height)
.attr('class', 'radial')
.append('g')
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
var extent = [0, d3.max(data, function(d) { return d.value; })];
var lastNum = extent[1];
var percentageOne = (lastNum*25)/100;
var percentageTwo = (lastNum*50)/100;
var percentageThree = (lastNum*75)/100;
var tickValues = [percentageOne, percentageTwo, percentageThree, lastNum];
var barScale = d3.scale.linear()
.domain(extent)
.range([0, barHeight]);
var keys = data.map(function(d, i) {
return d.name;
});
var numBars = keys.length;
// X scale
var x = d3.scale.linear()
.domain(extent)
.range([0, -barHeight]);
// X axis
var xAxis = d3.svg.axis()
.scale(x).orient('left')
.tickFormat(formatNumber)
.tickValues(tickValues);
// Inner circles
var circles = svg.selectAll('circle')
.data(tickValues)
.enter().append('circle')
.attr('r', function(d) {
return barScale(d);
})
.style('fill', 'none')
.style('stroke-width', '0.5px');
// Create arcs
var arc = d3.svg.arc()
.startAngle(function(d, i) {
var a = (i * 2 * Math.PI) / numBars;
var b = ((i + 1) * 2 * Math.PI) / numBars;
var d = (b - a) / 4;
var x = a + d;
var y = b - d;
return x; //(i * 2 * Math.PI) / numBars;
})
.endAngle(function(d, i) {
var a = (i * 2 * Math.PI) / numBars;
var b = ((i + 1) * 2 * Math.PI) / numBars;
var d = (b - a) / 4;
var x = a + d;
var y = b - d;
return y; //((i + 1) * 2 * Math.PI) / numBars;
})
.innerRadius(0);
// Render colored arcs
var segments = svg.selectAll('path')
.data(data)
.enter().append('path')
.each(function(d) {
d.outerRadius = 0;
})
.attr('class', 'bar')
.style('fill', function(d) {
return d.color;
})
.attr('d', arc);
// Animate segments
segments.transition().ease('elastic').duration(1000).delay(function(d, i) {
return (25 - i) * 10;
})
.attrTween('d', function(d, index) {
var i = d3.interpolate(d.outerRadius, barScale(+d.value));
return function(t) {
d.outerRadius = i(t);
return arc(d, index);
};
});
// Outer circle
svg.append('circle')
.attr('r', barHeight)
.classed('outer', true)
.style('fill', 'none')
.style('stroke-width', '.5px');
// Apply x axis
svg.append('g')
.attr('class', 'x axis')
.call(xAxis);
// Labels
var labelRadius = barHeight * 1.025;
var labels = svg.selectAll('foo')
.data(data)
.enter()
.append('g')
.classed('labels', true);
labels.append('def')
.append('path')
.attr('id', function(d, i) { return 'label-path' + i; })
.attr('d', function(d) {
return 'm0 ' + -(barScale(d.value) + 4) + ' a' + (barScale(d.value) + 4) + ' ' + (barScale(d.value) + 4) + ' 0 1,1 -0.01 0';
});
labels.append('def')
.append('path')
.attr('id', function(d, i) { return 'label-pathnum' + i; })
.attr('d', function(d){
return 'm0 ' + -(barScale(d.value) + 14) + ' a' + (barScale(d.value) + 14) + ' ' + (barScale(d.value) + 14) + ' 0 1,1 -0.01 0';
});
labels.append('text')
.style('text-anchor', 'middle')
.style('fill', function(d, i) {
return d.color;
})
.append('textPath')
.attr('xlink:href', function(d, i) { return '#label-path' + i; })
.attr('startOffset', function(d, i) {
return i * 100 / numBars + 50 / numBars + '%';
})
.text(function(d) {
return d.name.toUpperCase();
});
labels.append('text')
.style('text-anchor', 'middle')
.style('fill', function(d, i) {
return d.color;
})
.append('textPath')
.attr('xlink:href', function(d, i) { return '#label-pathnum' + i; })
.attr('startOffset', function(d, i) {
return i * 100 / numBars + 50 / numBars + '%';
})
.text(function(d) {
return d.value;
});
You need to modify the path for the specific elements that need to be flipped. To do this, I start by storing the angle in your data object:
.each(function(d,i) {
d.outerRadius = 0;
var angleStart = (i/numBars) * 360;
var angleEnd = ((i+1)/numBars) * 360;
d.angle = (angleStart + angleEnd) / 2;
})
Then I tested the angle when creating the paths for the text and I reverse the path for the flipped text case:
var len = barScale(d.value) + 4;
if(d.angle > 91 && d.angle < 269) {
len += 8; // the flipped text is on the inside of the path so we need to draw it further out
return 'M -0.01 ' + (-len) + ' A ' + len + ' ' + len + ' 0 1,0 0 ' + (-len);
}
else {
return 'M 0 ' + (-len) + ' A' + len + ' ' + len + ' 0 1,1 -0.01 ' + (-len);
}
Then, you need to flip your '% around the path' for the placement of the text along the reversed path:
.attr('startOffset', function(d, i) {
if(d.angle > 91 && d.angle < 269)
return (100 - (i * 100 / numBars + 50 / numBars)) + '%';
else
return i * 100 / numBars + 50 / numBars + '%';
})
Working fiddle can be found here: https://jsfiddle.net/FrancisMacDougall/mnrqokqL/
With this result:
Here is the image sample how I want to look alike:
http://i.stack.imgur.com/ro2kQ.png
I was making a pie chart but I want to add a line to that label-> value.
Any help would be appreciated.
http://jsfiddle.net/28zv8n65/
Here is ;
arcs.append("svg:text")
.attr("transform", function(d) { //set the label's origin to the center of the arc
//we have to make sure to set these before calling arc.centroid
d.outerRadius = outerRadius + 50; // Set Outer Coordinate
d.innerRadius = outerRadius + 45; // Set Inner Coordinate
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle") //center the text on it's origin
.style("fill", "Purple")
.style("font", "bold 12px Arial")
.text(function(d, i) { return dataSet[i].label; });
Try this code.
var labelr = outerRadius+60;
//Draw labels
arcs.append("svg:text")
.attr("text-anchor", "middle") //center the text on it's origin
.style("fill", "Purple")
.style("font", "bold 12px Arial")
.text(function(d, i) { return dataSet[i].label; })
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cx = Math.cos(a) * (labelr - 75);
return d.x = Math.cos(a) * (labelr - 20);
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cy = Math.sin(a) * (labelr - 75);
return d.y = Math.sin(a) * (labelr - 20);
})
.each(function(d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width/2 - 2;
d.ox = d.x + bbox.width/2 + 2;
d.sy = d.oy = d.y + 5;
});
//Draw pointer lines
arcs
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("d", function(d) {
if(d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
});
Code refered from d3.js pie chart with angled/horizontal labels
here is my simple code for d3 scalable map:
winWidth = $(window).width();
winHeight = $(window).height();
projection = d3.geo.mercator()
.translate([0, 0])
.scale(winWidth / 2 / Math.PI);
zoom = d3.behavior.zoom()
.scaleExtent([1, 50])
.on("zoom", manageMap);
path = d3.geo.path()
.projection(projection);
svg = d3.select("#map").append("svg")
.attr("viewBox", "0 0 " + winWidth + " " + winHeight)
.attr("preserveAspectRatio", "xMidYMid meet")
.append("g")
.attr("transform", "translate(" + winWidth / 2 + "," + winHeight / 2 + ")")
.call(zoom);
g = svg.append("g");
d3.json("world-50m.json", function(error, world) {
g.append("path")
.datum(topojson.feature(world, world.objects.countries))
.attr("class", "land")
.attr("d", path);
g.append("path")
.datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }))
.attr("class", "boundary")
.attr("d", path);
});
function manageMap() {
var t = d3.event.translate,
s = d3.event.scale;
t[0] = Math.min(winWidth / 2 * (s - 1), Math.max(winWidth / 2 * (1 - s), t[0]));
t[1] = Math.min(winHeight / 2 * (s - 1) + 230 * s, Math.max(winHeight / 2 * (1 - s) - 230 * s, t[1]));
zoom.translate(t);
g.style("stroke-width", 1/s).attr("transform", "translate(" + t + ")scale(" + s + ")");
svg.select("g").selectAll("circle")
.attr("cx", function(d) { return projection([d.lng, d.lat])[0]; })
.attr("cy", function(d) { return projection([d.lng, d.lat])[1]; })
.attr("r", 11/s);
}
Is there any simple way to have current visible area coordinates, when map is scaled and translated? I'm already try to project translation of map, but just got some strange numbers.
This will do it. I've also put it up on http://bl.ocks.org/sfinktah/1d38c8a268d893d769ed
Even if you have found your solution, this may be useful for future googlers.
function getScreenBounds() {
return [getPoint(0,0), getPoint()];
}
function getPoint(x,y) {
if (x == null) x = winWidth;
if (y == null) y = winHeight;
var container = g.node();
var svg = container.ownerSVGElement || container;
var point = svg.createSVGPoint();
point.x = x, point.y = y;
point = point.matrixTransform(container.getScreenCTM().inverse());
return formatLocation(projection.invert([point.x, point.y]), zoom.scale());
}
function formatLocation(p, k) {
var format = d3.format("." + Math.floor(Math.log(k) / 2 - 2) + "f");
return (p[1] < 0 ? format(-p[1]) + "°S" : format(p[1]) + "°N") + " "
+ (p[0] < 0 ? format(-p[0]) + "°W" : format(p[0]) + "°E");
}
This time I am stuck in a circular axis for meter readings. I want to make readings and ticks along the circular path for meter gauge (just like speedometer):
However, I am not getting the exact idea or solution for it. Also, to be specific, I want to do it with D3.js only.
I have created the meter with some references, and tried to pull out some readings in it so far, but I don't feel what I have done is the most appropriate way to do this.
Please guide me through this. Here is my code : -
<!DOCTYPE html>
<meta charset="utf-8">
<title>Speedo-meter</title>
<script src="jquery-1.9.1.min.js"></script>
<style>
svg
{
margin-left: 30px;
margin-top: 30px;
border: 1px solid #ccc;
}
</style>
<body>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script>
var data = {
"title": "Meter Gauge",
"value": 50,
"maxValue": 200
};
startAngle = 90, endAngle = 270, innerRad=175 , outerRad=185 ;
var svg = d3.selectAll("body").append("svg")
.attr("width", 500)
.attr("height", 500);
var arc = d3.svg.arc()
.innerRadius(innerRad)
.outerRadius(outerRad)
.startAngle(90 * (Math.PI/180))
.endAngle(270 * (Math.PI/180));
var title = svg.append("text")
.attr("x", 50)
.attr("y", 50)
.style("text-anchor", "start")
.text("Click on the meter line to turn the needle");
var plot = svg.append("g")
.attr("class", "arc")
.attr("transform", "translate(100 , 150 )");
var gauge = plot.append("path")
.attr("d", arc)
.attr("class", "gauge")
.attr("fill", "#ddd")
.attr("stroke", "#000")
.attr("transform", "translate(150,130) rotate(180)")
.on("click", turnNeedle);
var needle = svg.append("g")
.attr("class", "needle")
.attr("transform", "translate( 100 , 110 )")
.append("path")
.attr("class", "tri")
.attr("d", "M" + (300/2 + 3) + " " + (120 + 10) + " L" + 300/2 + " 0 L" + (300/2 - 3) + " " + (120 + 10) + " C" + (300/2 - 3) + " " + (120 + 20) + " " + (300/2 + 3) + " " + (120 + 20) + " " + (300/2 + 3) + " " + (120 + 10) + " Z")
.attr("transform", "rotate(-100, " + 300/2 + "," + (120 + 10) + ")");
function turnNeedle()
{
needle.transition()
.duration(2000)
.attrTween("transform", tween);
//console.log(d3.select(".needle").attr("cx"));
function tween(d, i, a) {
return d3.interpolateString("rotate(-100, 150, 130)", "rotate(100, 150, 130)");
}
}
var Speeds = data.maxValue/20;
var divisions = ((endAngle-startAngle))/Speeds ;
console.log("divisions=>"+divisions);
j=0;
endAngle1 = startAngle+ 20;
startAngle = 72;
for(i=0;i<=10;i++)
{
endAngle = startAngle+ divisions;
newArc = d3.svg.arc()
.innerRadius(innerRad - 10)
.outerRadius(outerRad)
.startAngle((startAngle+=divisions) * (Math.PI/180))
.endAngle(endAngle * (Math.PI/180));
var gauge = plot.append("path")
.attr("d",newArc)
.attr("class", "gauge")
.attr("id", "gauge"+i)
.attr("fill", "#ddd")
.attr("stroke", "#000")
.attr("transform", "translate(150,130) rotate(180)")
.on("click", turnNeedle);
var text = plot.append("text")
.style("font-size",14)
.style("fill","#000")
.style("text-anchor", "start")
.attr("x", -165 + 6)
.attr("dy",".35em")
.append("textPath")
.attr("xlink:href","#gauge"+i)
.attr("startOffset",5)
.text(Speeds*i);
}
</script>