d3 as Vue component - d3.js
I want to make a Gauge from d3.js as a component I can use in Vue. But I'm struggling import it the right way so I can wrap it in a custom component.
Besides installed the d3 from npm: npm install d3. I have this for the gauge
// data which need to be fetched
var name = " ";
var value = 840;
var gaugeMaxValue = 1680;
// donn�es � calculer
var percentValue = value / gaugeMaxValue;
////////////////////////
var needleClient;
(function(){
var barWidth, chart, chartInset, degToRad, repaintGauge,
height, margin, numSections, padRad, percToDeg, percToRad,
percent, radius, sectionIndx, svg, totalPercent, width,
valueText, formatValue, k;
percent = percentValue;
numSections = 1;
sectionPerc = 1 / numSections / 2;
padRad = 0.025;
chartInset = 10;
// Orientation of gauge:
totalPercent = .75;
el = d3.select('.chart-gauge');
margin = {
top: 30,
right: 30,
bottom: 30,
left: 30
};
width = el[0][0].offsetWidth - margin.left - margin.right;
height = width;
radius = Math.min(width, height) / 2;
barWidth = 40 * width / 300;
//Utility methods
percToDeg = function(perc) {
return perc * 360;
};
percToRad = function(perc) {
return degToRad(percToDeg(perc));
};
degToRad = function(deg) {
return deg * Math.PI / 180;
};
// Create SVG element
svg = el.append('svg').attr('width', width + margin.left + margin.right).attr('height', height + margin.top + margin.bottom);
// Add layer for the panel
chart = svg.append('g').attr('transform', "translate(" + ((width) / 2 + margin.left) + ", " + ((height + margin.top) / 2) + ")");
chart.append('path').attr('class', "arc chart-red");
chart.append('path').attr('class', "arc chart-yellow");
chart.append('path').attr('class', "arc chart-green");
chart.append('path').attr('class', "arc chart-yellow_");
chart.append('path').attr('class', "arc chart-red_");
valueText = chart.append("chart")
formatValue = d3.format('1%');
arc5 = d3.svg.arc().outerRadius(radius - chartInset).innerRadius(radius - chartInset - barWidth)
arc4 = d3.svg.arc().outerRadius(radius - chartInset).innerRadius(radius - chartInset - barWidth)
arc3 = d3.svg.arc().outerRadius(radius - chartInset).innerRadius(radius - chartInset - barWidth)
arc2 = d3.svg.arc().outerRadius(radius - chartInset).innerRadius(radius - chartInset - barWidth)
arc1 = d3.svg.arc().outerRadius(radius - chartInset).innerRadius(radius - chartInset - barWidth)
repaintGauge = function ()
{
perc = 0.5;
var next_start = totalPercent;
arcStartRad = percToRad(next_start);
arcEndRad = arcStartRad + percToRad(0.175);
next_start += 0.175;
arc1.startAngle(arcStartRad).endAngle(arcEndRad);
arcStartRad = percToRad(next_start);
arcEndRad = arcStartRad + percToRad(0.05);
next_start += 0.05;
arc2.startAngle(arcStartRad + padRad).endAngle(arcEndRad);
arcStartRad = percToRad(next_start);
arcEndRad = arcStartRad + percToRad(0.05);
next_start += 0.05;
arc3.startAngle(arcStartRad + padRad).endAngle(arcEndRad);
arcStartRad = percToRad(next_start);
arcEndRad = arcStartRad + percToRad(0.05);
next_start += 0.05;
arc4.startAngle(arcStartRad + padRad).endAngle(arcEndRad);
arcStartRad = percToRad(next_start);
arcEndRad = arcStartRad + percToRad(0.175);
next_start += 0.175;
arc5.startAngle(arcStartRad + padRad).endAngle(arcEndRad);
chart.select(".chart-red").attr('d', arc1);
chart.select(".chart-yellow").attr('d', arc2);
chart.select(".chart-green").attr('d', arc3);
chart.select(".chart-yellow_").attr('d', arc4);
chart.select(".chart-red_").attr('d', arc5);
}
/////////
var Needle = (function() {
//Helper function that returns the `d` value for moving the needle
var recalcPointerPos = function(perc) {
var centerX, centerY, leftX, leftY, rightX, rightY, thetaRad, topX, topY;
thetaRad = percToRad(perc / 2);
centerX = 0;
centerY = 0;
topX = centerX - this.len * Math.cos(thetaRad);
topY = centerY - this.len * Math.sin(thetaRad);
leftX = centerX - this.radius * Math.cos(thetaRad - Math.PI / 2);
leftY = centerY - this.radius * Math.sin(thetaRad - Math.PI / 2);
rightX = centerX - this.radius * Math.cos(thetaRad + Math.PI / 2);
rightY = centerY - this.radius * Math.sin(thetaRad + Math.PI / 2);
return "M " + leftX + " " + leftY + " L " + topX + " " + topY + " L " + rightX + " " + rightY;
};
function Needle(el) {
this.el = el;
this.len = width / 2.5;
this.radius = this.len / 8;
}
Needle.prototype.render = function() {
this.el.append('circle').attr('class', 'needle-center').attr('cx', 0).attr('cy', 0).attr('r', this.radius);
return this.el.append('path').attr('class', 'needle').attr('id', 'client-needle').attr('d', recalcPointerPos.call(this, 0));
};
Needle.prototype.moveTo = function(perc) {
var self,
oldValue = this.perc || 0;
this.perc = perc;
self = this;
// Reset pointer position
this.el.transition().delay(100).ease('quad').duration(200).select('.needle').tween('reset-progress', function() {
return function(percentOfPercent) {
var progress = (1 - percentOfPercent) * oldValue;
repaintGauge(progress);
return d3.select(this).attr('d', recalcPointerPos.call(self, progress));
};
});
this.el.transition().delay(300).ease('bounce').duration(1500).select('.needle').tween('progress', function() {
return function(percentOfPercent) {
var progress = percentOfPercent * perc;
repaintGauge(progress);
var thetaRad = percToRad(progress / 2);
var textX = - (self.len + 45) * Math.cos(thetaRad);
var textY = - (self.len + 45) * Math.sin(thetaRad);
valueText.text(formatValue(progress))
.attr('transform', "translate("+textX+","+textY+")")
return d3.select(this).attr('d', recalcPointerPos.call(self, progress));
};
});
};
return Needle;
})();
needle = new Needle(chart);
needle.render();
needle.moveTo(percent);
setTimeout(displayValue, 1350);
})();
This is the working HTML but not as a component
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css" src="gauge.css">
.chart-gauge
{
width: 400px;
margin: 100px auto
}
.chart-green
{
fill: #9FBD35;
}
.chart-yellow
{
fill: #F2BA3A;
}
.chart-yellow_
{
fill: #F2BA3A;
}
.chart-red
{
fill: #FB3033;
}
.chart-red_
{
fill: #FB3033;
}
.needle, .needle-center
{
fill: #000000;
}
.text {
color: "#112864";
font-size: 16px;
}
svg {
font: 10px sans-serif;
}
</style>
</head>
<body>
<div class="chart-gauge"></div>
<script type="text/javascript" src="./gaugeClient.js"></script>
<script type="text/javascript" src="./labels.js"></script>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</body>
</html>
First component are designed to help you from rewriting your code each and every time , so why not create a component for d3 that you can reuse each and everytime like below :
universal c3 component, c3.vue
<template>
<div :style="style" v-bind:class="class" id="{{ randomid }}" ></div>
</template>
<script>
import c3 from 'c3'
module.exports = {
props: {
legend: {
type: Object,
},
size: {
type: Object,
},
colour: {
type: Object,
},
axis: {
type: Object,
},
bar: {
type: Object,
},
chartdata:{
type: Object,
default: function () {
return {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25]
]
}
}
},
class:{
type: Object,
},
styles: {
type: Object,
}
},
created: function() {
},
ready: function(){
this.drawChart();
},
methods : {
drawChart: function () {
var self = this
var chart = c3.generate({
bindto: document.getElementById(self.randomid) ,
data: self.chartdata,
size : self.size,
colour : self.colour,
legend : self.legend,
bar : self.bar,
axis : self.axis
});
}
},
computed: {
randomid: function () {
return _.uniqueId('c3_')
}
}
}
</script>
next register the component :
Vue.component('c3-chart', require('./c3.vue'))
now you can use this to create any chart you want , yes + gauges
<template>
<div>
<c3-chart :chartdata="gauge.data" :colour="gauge.colour" :size="gauge.size"></c3-chart>
</div>
</template>
<script>
module.exports = {
props: {
},
components: {
},
data: function () {
return {
gauge : {
data: {
columns: [
['data', 91.4]
],
type: 'gauge',
onclick: function (d, i) { console.log("onclick", d, i); },
onmouseover: function (d, i) { console.log("onmouseover", d, i); },
onmouseout: function (d, i) { console.log("onmouseout", d, i); }
},
color: {
pattern: ['#FF0000', '#F97600', '#F6C600', '#60B044'],
threshold: {
values: [30, 60, 90, 100]
}
},
size: {
height: 180
}
}
}
},
created: function() {
},
ready: function(){
},
methods : {
},
events: {
},
computed: {
}
}
</script>
Related
D3 x3dom - 3d scatter plot
I'm trying to reproduce an 3d-ScatterPlot using the d3 library. The example is written in v3 and I'm having difficulties to recreate it in v5. The issue is that the axis don't get drawn. function drawAxis( axisIndex, key, duration ) { var scale = d3.scaleLinear() .domain( [-5,5] ) // demo data range .range( axisRange ) scales[axisIndex] = scale; var numTicks = 8; var tickSize = 0.1; var tickFontSize = 0.5; // ticks along each axis var ticks = scene.selectAll( "."+axisName("Tick", axisIndex) ) .data( scale.ticks( numTicks )); var newTicks = ticks.enter() .append("transform") .attr("class", axisName("Tick", axisIndex)); newTicks.append("shape").call(makeSolid) .append("box") .attr("size", tickSize + " " + tickSize + " " + tickSize); // enter + update ticks.attr("translation", function(tick) { return constVecWithAxisValue( 0, scale(tick), axisIndex ); }) ticks.exit().remove(); // tick labels var tickLabels = ticks.selectAll("billboard shape text") .data(function(d) { return [d]; }); var newTickLabels = tickLabels.enter() .append("billboard") .attr("axisOfRotation", "0 0 0") .append("shape") .call(makeSolid) newTickLabels.append("text") .attr("string", scale.tickFormat(10)) .attr("solid", "true") .append("fontstyle") .attr("size", tickFontSize) .attr("family", "SANS") .attr("justify", "END MIDDLE" ); tickLabels // enter + update .attr("string", scale.tickFormat(10)) tickLabels.exit().remove(); // base grid lines if (axisIndex==0 || axisIndex==2) { var gridLines = scene.selectAll( "."+axisName("GridLine", axisIndex)) .data(scale.ticks( numTicks )); gridLines.exit().remove(); var newGridLines = gridLines.enter() .append("transform") .attr("class", axisName("GridLine", axisIndex)) .attr("rotation", axisIndex==0 ? [0,1,0, -Math.PI/2] : [0,0,0,0]) .append("shape") newGridLines.append("appearance") .append("material") .attr("emissiveColor", "gray") newGridLines.append("polyline2d"); gridLines.selectAll("shape polyline2d").attr("lineSegments", "0 0, " + axisRange[1] + " 0") gridLines.attr("translation", axisIndex==0 ? function(d) { return scale(d) + " 0 0"; } : function(d) { return "0 0 " + scale(d); } ) } } My guess is that the issue is in this method. I created a full example here: https://codepen.io/anon/pen/aevWQX Thanks for your help!
From v4 onward, you need to .merge() your newly added .enter() selection and your existing selection, otherwise the result is an empty selection - which is why the code was executed, only not applied to any elements. var x3d = d3.select("#divPlot") .append("x3d") .style("width", "500px") .style("height", "500px") .style("border", "none") var scene = x3d.append("scene") scene.append("orthoviewpoint") .attr("centerOfRotation", [5, 5, 5]) .attr("fieldOfView", [-5, -5, 15, 15]) .attr("orientation", [-0.5, 1, 0.2, 1.12 * Math.PI / 4]) .attr("position", [8, 4, 15]) var rows = initializeDataGrid(); var axisRange = [0, 10]; var scales = []; var initialDuration = 0; var defaultDuration = 800; var ease = 'linear'; var time = 0; var axisKeys = ["x", "y", "z"] // Helper functions for initializeAxis() and drawAxis() function axisName(name, axisIndex) { return ['x', 'y', 'z'][axisIndex] + name; } function constVecWithAxisValue(otherValue, axisValue, axisIndex) { var result = [otherValue, otherValue, otherValue]; result[axisIndex] = axisValue; return result; } // Used to make 2d elements visible function makeSolid(selection, color) { selection.append("appearance") .append("material") .attr("diffuseColor", color || "black") return selection; } // Initialize the axes lines and labels. function initializePlot() { initializeAxis(0); initializeAxis(1); initializeAxis(2); } function initializeAxis(axisIndex) { var key = axisKeys[axisIndex]; drawAxis(axisIndex, key, initialDuration); var scaleMin = axisRange[0]; var scaleMax = axisRange[1]; // the axis line var newAxisLine = scene.append("transform") .attr("class", axisName("Axis", axisIndex)) .attr("rotation", ([ [0, 0, 0, 0], [0, 0, 1, Math.PI / 2], [0, 1, 0, -Math.PI / 2] ][axisIndex])) .append("shape") newAxisLine .append("appearance") .append("material") .attr("emissiveColor", "lightgray") newAxisLine .append("polyline2d") // Line drawn along y axis does not render in Firefox, so draw one // along the x axis instead and rotate it (above). .attr("lineSegments", "0 0," + scaleMax + " 0") // axis labels var newAxisLabel = scene.append("transform") .attr("class", axisName("AxisLabel", axisIndex)) .attr("translation", constVecWithAxisValue(0, scaleMin + 1.1 * (scaleMax - scaleMin), axisIndex)) var newAxisLabelShape = newAxisLabel .append("billboard") .attr("axisOfRotation", "0 0 0") // face viewer .append("shape") .call(makeSolid) var labelFontSize = 0.6; newAxisLabelShape .append("text") .attr("class", axisName("AxisLabelText", axisIndex)) .attr("solid", "true") .attr("string", key) .append("fontstyle") .attr("size", labelFontSize) .attr("family", "SANS") .attr("justify", "END MIDDLE") } // Assign key to axis, creating or updating its ticks, grid lines, and labels. function drawAxis(axisIndex, key, duration) { var scale = d3.scaleLinear() .domain([-5, 5]) // demo data range .range(axisRange) scales[axisIndex] = scale; var numTicks = 8; var tickSize = 0.1; var tickFontSize = 0.5; // ticks along each axis var ticks = scene.selectAll("." + axisName("Tick", axisIndex)) .data(scale.ticks(numTicks)); var newTicks = ticks.enter() .append("transform") .attr("class", axisName("Tick", axisIndex)); newTicks.append("shape").call(makeSolid) .append("box") .attr("size", tickSize + " " + tickSize + " " + tickSize); // enter + update ticks.attr("translation", function(tick) { return constVecWithAxisValue(0, scale(tick), axisIndex); }) ticks.exit().remove(); // tick labels var tickLabels = ticks.selectAll("billboard shape text") .data(function(d) { return [d]; }); var newTickLabels = tickLabels.enter() .append("billboard") .attr("axisOfRotation", "0 0 0") .append("shape") .call(makeSolid) newTickLabels.append("text") .attr("string", scale.tickFormat(10)) .attr("solid", "true") .append("fontstyle") .attr("size", tickFontSize) .attr("family", "SANS") .attr("justify", "END MIDDLE"); tickLabels // enter + update .attr("string", scale.tickFormat(10)) tickLabels.exit().remove(); // base grid lines if (axisIndex == 0 || axisIndex == 2) { debugger; var gridLines = scene.selectAll("." + axisName("GridLine", axisIndex)) .data(scale.ticks(numTicks)); gridLines.exit().remove(); var newGridLines = gridLines.enter() .append("transform") .attr("class", axisName("GridLine", axisIndex)) .attr("rotation", axisIndex == 0 ? [0, 1, 0, -Math.PI / 2] : [0, 0, 0, 0]) .append("shape") newGridLines.append("appearance") .append("material") .attr("emissiveColor", "gray") newGridLines.append("polyline2d"); gridLines = newGridLines .merge(gridLines); gridLines.selectAll("shape polyline2d").attr("lineSegments", "0 0, " + axisRange[1] + " 0") gridLines.attr("translation", axisIndex == 0 ? function(d) { return scale(d) + " 0 0"; } : function(d) { return "0 0 " + scale(d); } ) } } // Update the data points (spheres) and stems. function plotData(duration) { if (!rows) { console.log("no rows to plot.") return; } var x = scales[0], y = scales[1], z = scales[2]; var sphereRadius = 0.2; // Draw a sphere at each x,y,z coordinate. var datapoints = scene.selectAll(".datapoint").data(rows); datapoints.exit().remove() var newDatapoints = datapoints.enter() .append("transform") .attr("class", "datapoint") .attr("scale", [sphereRadius, sphereRadius, sphereRadius]) .append("shape"); newDatapoints .append("appearance") .append("material"); newDatapoints .append("sphere") // Does not work on Chrome; use transform instead //.attr("radius", sphereRadius) datapoints.selectAll("shape appearance material") .attr("diffuseColor", 'steelblue') datapoints.transition().ease(d3.easeLinear).duration(duration) .attr("translation", function(row) { return x(row[axisKeys[0]]) + " " + y(row[axisKeys[1]]) + " " + z(row[axisKeys[2]]) }) } function initializeDataGrid() { var rows = []; // Follow the convention where y(x,z) is elevation. for (var x = -5; x <= 5; x += 1) { for (var z = -5; z <= 5; z += 1) { rows.push({ x: x, y: 0, z: z }); } } return rows; } function updateData() { time += Math.PI / 8; if (x3d.node() && x3d.node().runtime) { for (var r = 0; r < rows.length; ++r) { var x = rows[r].x; var z = rows[r].z; rows[r].y = 5 * (Math.sin(0.5 * x + time) * Math.cos(0.25 * z + time)); } plotData(defaultDuration); } else { console.log('x3d not ready.'); } } initializeDataGrid(); initializePlot(); setInterval(updateData, defaultDuration); .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .axis text { font: 10px sans-serif; } <html> <head> <meta http-equiv="X-UA-Compatible" content="chrome=1" /> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>3D Scatter Plot</title> <!--<script type="text/javascript" src="http://d3js.org/d3.v5.min.js"></script>--> <script type="text/javascript" src="http://d3js.org/d3.v5.js"></script> <script type="text/javascript" src="http://x3dom.org/x3dom/dist/x3dom-full.js"></script> <link rel="stylesheet" type="text/css" href="http://www.x3dom.org/download/dev/x3dom.css" /> </head> <body> <div id="divPlot" style="width: 500px; height: 500px;"></div> </body> </html> The only change I made is the call to .merge somewhere inside the if statement in drawAxis. Hope this helps!
Fill not working with areaRadial() generated shape
I'm currently working on a thing which is supposed to look like a lava lamp later. Unfortunately, I'm already failing at the beginning: I managed to create randomly generated blobs, but I just can't apply a fill. The stroke works just fine. here is the relevant code which creates the blobs: var ctx = this; // context this.path = d3.areaRadial() .angle(function(d) {return d.theta}) .radius(function(d) {return d.r}) .curve(d3.curveCatmullRomClosed.alpha(1)); // create the blob this.create = function() { var anchors = []; for (var i = 0; i < ctx.options.anchors; i++) { var currTheta = i * (360 / ctx.options.anchors) + rand(ctx.options.spread.theta); var currRadians = Math.radians(currTheta); var currRadius = ctx.options.radius + rand(ctx.options.spread.r); anchors.push({theta: currRadians, r: currRadius}); } var pathData = ctx.path(anchors); d3.select(ctx.options.target).append('path') .attr('d', pathData) .attr('class', 'blob') .style('opacity', ctx.options.opacity) .style('transform', 'translate(' + ctx.x + 'px, ' + ctx.y + 'px)') .attr('transform', 'translate(' + ctx.x + 'px, ' + ctx.y + 'px)'); console.log(pathData); } function rand(x) // creates a random number between -0.5 * x and 0.5 * x Full code: https://codepen.io/normanwink/pen/BrMVrE Thanks!
That's the expected behaviour, since you're using radius, which is: Equivalent to area.y, except the accessor returns the radius: the distance from the origin ⟨0,0⟩. And for area.y: If y is specified, sets y0 to y and y1 to null and returns this area generator. If y is not specified, returns the current y0 accessor. (emphasis mine) Therefore, you probably want outerRadius here. this.path = d3.areaRadial() .angle(function(d) { return d.theta }) .outerRadius(function(d) { return d.r }) .curve(d3.curveCatmullRomClosed.alpha(1)); This is your code with that change only: (function() { "use strict"; // window size var windowX = window.innerWidth; var windowY = window.innerHeight; var svgX = windowX; var svgY = windowY; var blobCount = 1; function init() { // console.log(new Blob()); var svg = d3.select('#svg') .attr('viewBox', '0 0 ' + svgX + ' ' + svgY) .attr('preserveAspectRatio', 'xMinYMin meet'); for (var i = 0; i < blobCount; i++) { var newBlob = new Blob(svgX * 0.5, svgY * 0.5); } } function Blob(x, y) { var ctx = this; // context this.options = { anchors: 8, breathe: 30, fill: '#ffffff', opacity: 0.5, radius: 150, spread: { theta: 10, // angle r: 300 // radius }, target: '#svg', }; this.x = x || 0; this.y = y || 0; this.path = d3.areaRadial() .angle(function(d) {return d.theta}) .outerRadius(function(d) {return d.r}) .curve(d3.curveCatmullRomClosed.alpha(1)); // create the blob this.create = function() { var anchors = []; for (var i = 0; i < ctx.options.anchors; i++) { var currTheta = i * (360 / ctx.options.anchors) + rand(ctx.options.spread.theta); var currRadians = Math.radians(currTheta); var currRadius = ctx.options.radius + rand(ctx.options.spread.r); anchors.push({theta: currRadians, r: currRadius}); } var pathData = ctx.path(anchors); d3.select(ctx.options.target).append('path') .attr('d', pathData) .attr('class', 'blob') .style('opacity', ctx.options.opacity) .style('transform', 'translate(' + ctx.x + 'px, ' + ctx.y + 'px)') .attr('transform', 'translate(' + ctx.x + 'px, ' + ctx.y + 'px)'); } // update position and anchor movement this.update = function() { } // apply changes this.render = function() { } this.create(); } function rand(i) { return (Math.random()-0.5) * (i || 1); } Math.radians = function(degrees) { return degrees * Math.PI / 180; }; // init when ready init(); })(); #svg { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; } .blob { fill: blue; /* why is this not working? */ stroke: red; } <script src="https://d3js.org/d3.v4.min.js"></script> <svg id="svg"></svg>
Your problem is your pathData , because if you replace your .attr('d', pathData) with .attr('d', 'M37,17v15H14V17z M50,0H0v50h50z') which is a valid path, your fill is working properly. I will continue searching the issue, just want to give you a hint, maybe you will find the issue faster then me. :)
Continent zoom topojson
I'm trying to make the map able to zoom in on continenents on mouseclick. The code is based on Mike Bostock's tutorial on making maps and uses a CSV dataset to bind some values to the countries. https://bost.ocks.org/mike/map/. I've tried to use various examples like this one: https://bl.ocks.org/mbostock/2206590 but nothing seems to work. The map just dissapears when I try to add a .onclick attribute. Does anyone have an idea how I can make the zoom work? HTML <!DOCTYPE html> <meta charset="utf-8"> <style> body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; width: 960px; height: 500px; position: relative; } #canvas { } #canvas-svg { } .land { fill: #222; } .boundary { fill: none; stroke: #fff; stroke-width: 1px; } #tooltip-container { position: absolute; background-color: #fff; color: #000; padding: 10px; border: 1px solid; display: none; } .tooltip_key { font-weight: bold; } .tooltip_value { margin-left: 20px; float: right; } </style> <div id="tooltip-container"></div> <div id="canvas-svg"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.20/topojson.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> <script> d3.csv("import.csv", function(err, data) { var config = {"data0":"Country","data1":"Total","label0":"label 0","label1":"label 1","color0":"#99ccff","color1":"#0050A1","width":800,"height":400} var width = 960, height = 960; var COLOR_COUNTS = 9; function Interpolate(start, end, steps, count) { var s = start, e = end, final = s + (((e - s) / steps) * count); return Math.floor(final); } function Color(_r, _g, _b) { var r, g, b; var setColors = function(_r, _g, _b) { r = _r; g = _g; b = _b; }; setColors(_r, _g, _b); this.getColors = function() { var colors = { r: r, g: g, b: b }; return colors; }; } function clicked(d) { var x, y, k; if (d && centered !== d) { var centroid = path.centroid(d); x = centroid[0]; y = centroid[1]; k = 4; centered = d; } else { x = width / 2; y = height / 2; k = 1; centered = null; } g.selectAll("path") .classed("active", centered && function(d) { return d === centered; }); g.transition() .duration(750) .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")") .style("stroke-width", 1.5 / k + "px"); } function hexToRgb(hex) { var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } function valueFormat(d) { if (d > 1000000000) { return "$" + Math.round(d / 1000000000 * 10) / 10 + "M"; } else if (d > 1000000) { return "$" + Math.round(d / 1000000 * 10) / 10 + "M"; } else if (d > 1000) { return "$" + Math.round(d / 1000 * 10) / 10 + "B"; } else { return "$" + d + "M"; } } var COLOR_FIRST = config.color0, COLOR_LAST = config.color1; var rgb = hexToRgb(COLOR_FIRST); var COLOR_START = new Color(rgb.r, rgb.g, rgb.b); rgb = hexToRgb(COLOR_LAST); var COLOR_END = new Color(rgb.r, rgb.g, rgb.b); var startColors = COLOR_START.getColors(), endColors = COLOR_END.getColors(); var colors = []; for (var i = 0; i < COLOR_COUNTS; i++) { var r = Interpolate(startColors.r, endColors.r, COLOR_COUNTS, i); var g = Interpolate(startColors.g, endColors.g, COLOR_COUNTS, i); var b = Interpolate(startColors.b, endColors.b, COLOR_COUNTS, i); colors.push(new Color(r, g, b)); } var MAP_KEY = config.data0; var MAP_VALUE = config.data1; var projection = d3.geo.mercator() .scale((width + 1) / 2 / Math.PI) .translate([width / 2, height / 2]) .precision(.1); var path = d3.geo.path() .projection(projection); var graticule = d3.geo.graticule(); var svg = d3.select("#canvas-svg").append("svg") .attr("width", width) .attr("height", height); svg.append("path") .datum(graticule) .attr("class", "graticule") .attr("d", path); var valueHash = {}; function log10(val) { return Math.log(val); } data.forEach(function(d) { valueHash[d[MAP_KEY]] = +d[MAP_VALUE]; }); var quantize = d3.scale.quantize() .domain([0, 1.0]) .range(d3.range(COLOR_COUNTS).map(function(i) { return i })); quantize.domain([d3.min(data, function(d){ return (+d[MAP_VALUE]) }), d3.max(data, function(d){ return (+d[MAP_VALUE]) })]); d3.json("./world-topo-min.json", function(error, world) { var countries = topojson.feature(world, world.objects.countries).features; svg.append("path") .datum(graticule) .attr("class", "choropleth") .attr("d", path); var g = svg.append("g"); g.append("path") .datum({type: "LineString", coordinates: [[-180, 0], [-90, 0], [0, 0], [90, 0], [180, 0]]}) .attr("class", "equator") .attr("d", path); var country = g.selectAll(".country").data(countries); country.enter().insert("path") .attr("class", "country") .attr("d", path) .attr("id", function(d,i) { return d.id; }) .attr("title", function(d) { return d.properties.name; }) .style("fill", function(d) { if (valueHash[d.properties.name]) { var c = quantize((valueHash[d.properties.name])); var color = colors[c].getColors(); return "rgb(" + color.r + "," + color.g + "," + color.b + ")"; } else { return "#ccc"; } }) .on("mousemove", function(d) { var html = ""; html += "<div class=\"tooltip_kv\">"; html += "<span class=\"tooltip_key\">"; html += d.properties.name; html += "</span>"; html += "<span class=\"tooltip_value\">"; html += (valueHash[d.properties.name] ? valueFormat(valueHash[d.properties.name]) : ""); html += ""; html += "</span>"; html += "</div>"; $("#tooltip-container").html(html); $(this).attr("fill-opacity", "0.8"); $("#tooltip-container").show(); var coordinates = d3.mouse(this); var map_width = $('.choropleth')[0].getBoundingClientRect().width; if (d3.event.pageX < map_width / 2) { d3.select("#tooltip-container") .style("top", (d3.event.layerY + 15) + "px") .style("left", (d3.event.layerX + 15) + "px"); } else { var tooltip_width = $("#tooltip-container").width(); d3.select("#tooltip-container") .style("top", (d3.event.layerY + 15) + "px") .style("left", (d3.event.layerX - tooltip_width - 30) + "px"); } }) .on("mouseout", function() { $(this).attr("fill-opacity", "1.0"); $("#tooltip-container").hide(); }); g.append("path") .datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; })) .attr("class", "boundary") .attr("d", path); }); function clicked(d) { if (active.node() === this) return reset(); active.classed("active", false); active = d3.select(this).classed("active", true); var bounds = path.bounds(d), dx = bounds[1][0] - bounds[0][0], dy = bounds[1][1] - bounds[0][1], x = (bounds[0][0] + bounds[1][0]) / 2, y = (bounds[0][1] + bounds[1][1]) / 2, scale = .9 / Math.max(dx / width, dy / height), translate = [width / 2 - scale * x, height / 2 - scale * y]; g.transition() .duration(750) .style("stroke-width", 1.5 / scale + "px") .attr("transform", "translate(" + translate + ")scale(" + scale + ")"); } function reset() { active.classed("active", false); active = d3.select(null); g.transition() .duration(750) .style("stroke-width", "1.5px") .attr("transform", ""); } d3.select(self.frameElement).style("height", height + "px"); }); </script> CSV ,Country,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,Total ,Afghanistan,,,34,,,35,3,41,150,344,377,660,521,235,288,74,2763 ,African Union**,,,,,,53,9,,10,,,,,2,,2,76 ,Albania,,,,2,,7,,5,,,,,15,7,7,7,50 ,Algeria,412,546,249,195,242,159,340,509,1529,1075,829,1115,889,373,487,636,9585 ,Angola,147,156,148,48,8,39,7,31,29,20,,,,31,2,61,726 ,Argentina,213,6,16,12,168,3,9,24,23,16,14,46,36,44,14,23,668 ,Armenia,,,,,118,,,1,,46,52,5,,16,,,238 ,Australia,338,1236,663,801,472,459,727,675,445,775,1507,1567,876,255,932,1574,13301 ,Austria,25,15,69,42,55,23,4,269,190,286,7,8,8,6,2,,1008 ,Azerbaijan,3,,89,,4,53,159,211,29,142,146,557,333,398,602,285,3012 ,Bahamas,33,,,,,3,,,,1,,,,,29,22,88 ,Bahrain,299,30,54,1,10,66,63,26,20,,103,1,26,78,10,,786 ,Bangladesh,203,266,41,8,32,10,221,88,13,,35,193,252,727,257,653,2997 ,Barbados,,,,,,,,10,10,10,,,,,,,29 ,Belarus,,,,,,6,140,,,3,,75,75,75,60,164,598 ,Belgium,35,29,56,21,15,3,27,174,203,90,32,21,32,46,103,49,934 ,Belize,1,,,,,,,,,,,,,,,,1 ,Benin,,,7,,,,,3,,1,0,0,20,2,,,33 ,Bhutan,,,,,0,,,,,,,,,,,1,1 ,Bolivia,19,,,5,1,1,9,2,3,5,1,25,12,1,46,7,136 ,Botswana,53,15,1,9,8,,,,,13,10,,,8,,,119 ,Brazil,122,626,213,100,81,224,179,189,179,189,318,312,311,223,284,289,3840 ,Brunei,,4,1,0,0,1,2,,,33,33,229,22,15,122,36,498 ,Bulgaria,,,,2,12,132,22,48,116,119,8,29,5,,,3,495 ,Burkina Faso,,,,,,12,1,4,,2,0,15,4,,5,6,48 ,Burundi,,1,3,,,,,,,1,2,,5,,,1,14 ,Cambodia,,,,,,,14,56,,4,34,,77,67,,,252 ,Cameroon,,7,6,,,5,2,,1,,10,,,39,107,2,177 ,Canada,570,538,428,152,352,124,104,456,408,106,236,351,211,194,306,395,4931 ,Cape Verde,1,,,,,,,,,2,,,10,,,,12 ,Central African Republic,,,,,,,9,,0,,,7,,,,,16 ,Chad,,16,,,,,17,20,75,35,38,1,4,59,57,,322 ,Chile,202,60,74,187,70,449,1095,662,397,335,475,316,62,51,125,114,4673 ,China,2552,2833,2891,2373,3316,3558,2900,1692,1892,1407,1045,1128,1703,1452,1184,1214,33140 ,Colombia,60,278,171,147,18,16,56,234,110,248,255,145,207,162,190,215,2510 ,Comoros,,,,,,,,,6,,,,1,,,,7 ,Democratic Republic of Congo,0,,,,,4,1,0,,1,27,,23,12,13,,81 ,Costa Rica,,,,,,,,,,,,,1,,1,,2 ,Cote d'Ivoire,0,,32,61,9,,,,,,,,,,6,6,113 ,Croatia,,57,2,24,8,,,15,99,4,10,17,17,,63,11,326 ,Cyprus,4,115,1,6,16,20,26,17,,,44,41,6,,,,295 ,Czech Republic,14,65,47,97,7,593,45,10,23,6,13,71,22,15,,0,1029 ,Denmark,50,153,51,54,228,120,83,146,95,129,17,,109,42,177,0,1455 ,Djibouti,1,,3,,4,7,,,,,,,6,5,12,7,44 ,Dominican Republic,13,5,0,8,35,2,,,,10,51,12,,,,1,137 ,DR Congo,88,15,12,,,19,17,,18,41,151,,10,1,,,374 ,Ecuador,,10,1,,15,48,17,2,102,77,90,68,88,11,53,1,583 ,Egypt,837,847,719,630,654,778,678,651,333,159,686,630,281,675,368,1475,10401 ,El Salvador,,,19,10,,,,,4,,,,2,,20,,55 ,Equatorial Guinea,,7,,,7,12,,28,30,68,3,82,65,2,92,,394 ,Eritrea,20,57,18,17,80,98,,4,,,,,,,,,293 ,Estonia,27,,1,13,8,23,7,19,29,43,13,1,2,18,2,22,228 ,Ethiopia,140,,20,174,239,,,,,,54,76,193,153,30,,1079 ,Finland,474,9,12,227,77,107,136,108,135,42,50,58,76,280,156,228,2172 ,France,107,66,43,57,93,2,67,74,5,76,103,33,91,107,17,34,976 ,Gabon,,,,,6,,20,18,,,22,5,1,2,,3,77 ,Gambia,,,,,5,,,,,16,,,,,,,21 ,Georgia,6,85,,1,37,92,97,155,91,36,,2,,5,1,,608 ,Germany,113,133,71,64,239,204,416,82,292,339,282,84,157,113,114,102,2804 ,Ghana,1,12,1,6,35,0,0,16,,11,2,76,39,63,14,13,290 ,Greece,708,787,400,2274,1368,405,731,1712,516,1229,652,80,37,52,199,762,11910 ,Guatemala,,,,,,,,,0,,,,2,,,33,35 ,Guinea,18,6,,2,,1,,0,,,4,1,4,,5,,40 ,Guyana,,7,3,,,,,,0,,,,,,,,10 ,Palestine,,,,,,,,,,,1,2,,,0,,3 ,Lebanon,0,0,3,0,1,0,9,,,20,20,,,,,,54 ,Honduras,,,,,,,,,0,,,0,0,20,13,6,39 ,Hungary,14,14,,,72,13,253,196,5,4,18,9,,2,7,,604 ,Iceland,,,,,,,,,,,,50,,,,,50 ,India,995,1321,1911,2878,2180,1161,1480,2299,1867,1945,3017,3706,4545,5291,3487,3078,41160 ,Indonesia,151,27,68,356,79,36,61,577,239,436,225,250,218,802,1136,683,5341 ,Iran,418,524,435,282,121,57,423,331,62,62,103,103,47,31,13,13,3025 ,Iraq,,,,,71,186,305,263,377,398,453,603,474,353,650,1215,5348 ,Ireland,0,45,22,,19,5,13,19,22,0,5,2,1,,40,41,232 ,Israel,368,131,349,189,852,1133,1122,862,676,153,67,85,120,153,510,617,7387 ,Italy,241,221,243,559,446,162,433,525,220,109,115,298,219,91,145,596,4623 ,Jamaica,,,,,,10,10,13,2,,1,,,1,,2,38 ,Japan,491,441,477,480,400,464,511,498,680,525,426,292,270,306,480,310,7050 ,Jordan,133,160,121,281,157,49,48,176,161,234,87,214,175,81,252,198,2526 ,Kazakhstan,121,139,20,,47,42,44,82,25,39,58,52,84,141,93,419,1406 ,Kenya,15,,,,,,,10,,,112,14,60,1,17,30,258 ,Kosovo,,,,,,,,,,,,,,,1,,1 ,Kuwait,245,67,23,45,2,12,5,279,5,9,85,113,31,73,692,366,2052 ,Kyrgyzstan,,,,9,5,3,2,,,,,,,,,,19 ,Laos,7,36,,0,,4,,,7,26,,14,19,19,,7,138 ,Latvia,3,13,3,25,12,4,9,49,44,11,14,27,9,5,5,1,234 ,Lebanon,4,,,,,1,,5,1,52,64,2,31,24,5,50,239 ,Lesotho,,6,,,1,,1,,,,,,,,,,8 ,Liberia,8,,,,,,,,,,,,,,,,8 ,Libya,1,14,15,16,26,24,8,73,120,10,44,349 ,Lithuania,6,16,12,1,47,9,52,4,27,27,8,1,1,73,3,21,308 ,Uganda,,,0,,,,,,,,,,,,,,0 ,Sri Lanka,1,,1,,,0,,,,,,,,,,,2 ,Luxembourg,,,,1,,,,,,7,7,,1,,,,16 ,Macedonia,14,112,,,,,0,,,,,,,1,,,128 ,Madagascar,,,,,,,,,,0,,,,0,,,0 ,Malawi,,,,,,,,,3,,,,1,2,2,,7 ,Malaysia,26,26,154,147,65,57,398,526,508,1512,421,5,47,71,73,190,4227 ,Maldives,,,,,,,15,,,,5,,,5,,,24 ,Mali,7,,1,,,13,,8,3,10,,,9,6,,,57 ,Malta,0,0,,,,18,,,,,,8,8,,12,,45 ,Mauritania,31,,26,7,,,,,,,9,5,11,10,5,,103 ,Mauritius,,,,,6,,,,,,,,,,45,,51 ,Mexico,227,152,97,31,320,33,75,,22,59,112,229,261,69,97,500,2284 ,Mongolia,,,,,,,,,14,,27,3,51,,,13,107 ,Morocco,125,11,156,12,14,101,47,27,46,39,306,1398,826,82,572,42,3803 ,Mozambique,0,,,1,,,,,,,,0,0,9,12,,22 ,Myanmar,16,149,157,83,194,160,175,138,93,52,63,664,478,237,300,320,3277 ,Namibia,,21,11,,16,,72,6,66,15,,1,57,9,2,,276 ,NATO**,,18,,,,,116,,,420,,,22,,,,576 ,Nepal,,11,9,9,34,6,,,1,,,3,,,5,14,91 ,Netherlands,125,178,244,125,127,102,320,240,157,288,193,149,376,332,10,86,3052 ,New Zealand,,45,17,107,49,10,5,81,2,48,58,23,25,26,79,56,631 ,Nicaragua,,,,,,,,14,,14,,,,,,,28 ,Niger,,,,14,,,,,8,1,0,,,13,3,9,48 ,Nigeria,36,7,6,62,6,,15,52,19,65,186,65,4,35,224,188,971 ,Macedonia,,0,,,,,,,,,,,,,,,0 ,Afghanistan,19,207,,,,,,,,,,,,,,,226 ,North Korea,18,28,9,8,8,5,15,5,5,4,1,,,,,,103 ,Norway,229,99,90,14,6,14,542,567,624,588,159,614,149,62,23,143,3921 ,Libya,,,,,,,,,,,,0,,,,,0 ,Oman,118,33,40,36,41,173,301,16,75,93,30,21,120,490,736,148,2469 ,Pakistan,175,408,541,628,455,421,338,670,1047,1214,2176,1063,1028,1144,752,735,12797 ,Palestine,,,,,,,,2,,14,6,,,,,,21 ,Panama,,,1,,,,,,,7,,,15,30,,,52 ,Papua New Guinea,,,,,,,,,,,,,,,3,,3 ,Paraguay,,6,,,4,1,,,,,3,8,7,0,,,29 ,Peru,24,5,16,22,47,368,193,172,,43,46,63,10,49,153,169,1380 ,Philippines,,10,5,10,34,12,23,16,10,1,3,63,16,75,12,158,449 ,PIJ (Israel/Palestine)*,,,,,,,,,,,,,0,,,,0 ,Poland,148,36,255,349,225,112,463,990,594,169,158,92,207,155,252,131,4336 ,Portugal,2,19,,29,70,157,220,60,144,369,892,168,40,13,4,11,2196 ,PRC (Israel/Palestine)*,,,,,,,,,,,,,,,0,,0 ,Qatar,14,11,11,11,,,,27,,286,30,198,319,73,55,655,1690 ,Romania,21,19,16,17,285,437,61,98,78,56,105,80,21,20,0,22,1335 ,Russian Federation,,,,,,,4,100,,8,22,11,98,153,206,88,690 ,Rwanda,14,,,,,,2,15,8,11,,,5,11,14,7,86 ,Saudi Arabia,85,61,567,167,1170,167,205,214,363,796,1070,1237,1080,1672,2782,3161,14796 ,Senegal,,,,,,15,9,18,6,4,4,20,,6,7,11,99 ,Serbia,1,27,,,,,,,,,16,,0,,,,44 ,Seychelles,,,,,,15,,,,,,8,,7,16,,45 ,Sierra Leone,,,,,,,9,,,,,2,0,1,,,12 ,Singapore,798,254,234,83,376,538,69,355,1113,1481,1020,935,828,780,683,98,9645 ,Slovakia,0,,27,,,4,,0,,9,9,,2,6,,,57 ,Slovenia,2,41,2,17,17,3,3,2,,6,40,28,,,,,162 ,Somalia,,,,,,,,,,,,,,3,,0,3 ,South Africa,6,18,,,,262,708,881,486,128,180,212,132,2,50,,3065 ,South Korea,1396,773,528,752,1059,804,1650,1755,1683,796,1250,1553,1066,182,715,245,16207 ,South Sudan,,,,,,,,37,44,1,,61,3,5,18,22,190 ,Spain,334,168,289,253,315,363,315,337,346,235,290,181,238,176,127,153,4119 ,Sri Lanka,297,161,45,35,49,58,97,89,71,,5,21,,,5,,934 ,Sudan,,106,49,204,293,132,65,33,128,89,182,173,119,196,61,27,1858 ,Suriname,2,,,,,,,,,,,,,7,,3,11 ,Swaziland,1,1,,,,,,,,,,,,,,,2 ,Sweden,204,165,75,64,47,78,122,41,44,54,51,191,206,52,43,43,1481 ,Switzerland,23,68,63,117,203,168,83,108,18,39,47,31,9,4,0,2,983 ,Syrian Arab Republic,64,28,45,69,25,35,100,20,276,193,298,368,371,361,15,,2267 ,Syria rebels*,,,,,,,,,,,,,1,1,0,,2 ,Taiwan (ROC),585,345,298,117,319,691,503,12,11,60,97,198,425,553,1084,681,5978 ,Tajikistan,,,,,,,13,7,,32,,,,3,,,55 ,Tanzania,3,,,51,,10,12,1,,25,,78,115,92,26,20,433 ,Thailand,85,117,152,131,114,70,47,8,13,64,49,270,289,392,93,185,2078 ,Timor-Leste,,,,,,,,,,,18,,,,,,18 ,Togo,,,,,,,,,,,1,,4,,16,,21 ,Tonga,,,,,,,,,,,,,,,,5,5 ,Trinidad and Tobago,11,0,2,,,,,6,,,24,12,12,,,46,113 ,Tunisia,,,83,1,,168,2,,3,,7,7,,38,43,6,357 ,Turkey,1190,510,905,330,257,1113,531,692,710,780,484,770,1503,650,1556,448,12427 ,Turkmenistan,,,,18,21,,,,7,36,14,236,115,69,102,122,739 ,UAE,247,186,222,685,1210,2170,2021,919,752,561,605,1210,1088,2235,731,1289,16128 ,Uganda,6,,34,,36,10,5,,5,23,37,471,219,20,,3,868 ,UIC (Somalia)*,,,,,,,0,,,,,,,,,,0 ,Ukraine,,,,,,,,,,,,,,,1,10,11 ,Ukraine Rebels*,,,,,,,,,,,,,,,24,,24 ,United Kingdom,871,1277,719,761,212,27,308,764,508,383,511,368,586,492,214,382,8381 ,United Nations**,31,,,,2,1,2,1,0,,,,,5,23,4,69 ,United States,330,487,499,592,560,520,641,819,951,968,1111,995,1180,802,566,565,11587 ,United Wa State (Myanmar)*,,1,,,,,,,,,,,,,,,1 ,Unknown country,,2,,0,,,,,12,,8,6,,30,31,51,139 ,Unknown rebel group*,,0,0,,,,,,,,,,,,,,0 ,Uruguay,4,,11,,,20,8,3,78,29,20,,,6,9,8,196 ,Uzbekistan,,8,9,,,,,,,,,,,,,62,79 ,Venezuela,108,103,50,15,9,21,380,774,737,358,208,594,680,1165,173,162,5535 ,Viet Nam,7,85,66,28,304,297,41,8,204,78,184,1039,766,362,1078,870,5414 ,Yemen,158,85,593,62,254,317,38,66,40,5,258,45,38,23,6,12,2000 ,Zambia,33,,2,,,0,30,5,2,,,1,66,,,24,161 ,Zimbabwe,3,10,,16,,25,25,,,,,,,,,,78
nvd3 trigger event brushend
I've started creating a graph with nvd3 and need to fetch the 'brushend' event. Ive found the following information on this topic: https://github.com/novus/nvd3/issues/942 how to add brush in nvd3 like d3 The following code works with the 'brush' event but not the 'brushend' var chart = nv.models.lineWithFocusChart(); chart.brushExtent([50,70]); chart.xAxis.tickFormat(d3.format(',f')); chart.x2Axis.tickFormat(d3.format(',f')); chart.yAxis.tickFormat(d3.format(',.2f')); chart.y2Axis.tickFormat(d3.format(',.2f')); chart.useInteractiveGuideline(true); chart.dispatch.on('brush', function(brush){ console.log(brush); } ); d3.select("#chart svg").datum(tmp).call(chart);
I fixed the problem by adding some lines to the lineChart.js file: nv.models.lineChart = function() { "use strict"; var lines = nv.models.line() , xAxis = nv.models.axis() , yAxis = nv.models.axis() , legend = nv.models.legend() , interactiveLayer = nv.interactiveGuideline() , tooltip = nv.models.tooltip() , lines2 = nv.models.line() , x2Axis = nv.models.axis() , y2Axis = nv.models.axis() , brush = d3.svg.brush() ; var margin = {top: 30, right: 20, bottom: 50, left: 60} , margin2 = {top: 0, right: 20, bottom: 20, left: 60} , color = nv.utils.defaultColor() , width = null , height = null , showLegend = true , showXAxis = true , showYAxis = true , rightAlignYAxis = false , useInteractiveGuideline = false , x , y , x2 , y2 , focusEnable = false , focusShowAxisY = false , focusShowAxisX = true , focusHeight = 50 , brushExtent = null , state = nv.utils.state() , defaultState = null , noData = null , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'brush', 'stateChange', 'changeState', 'renderEnd', 'brushend') , duration = 250 ; // set options on sub-objects for this chart xAxis.orient('bottom').tickPadding(7); yAxis.orient(rightAlignYAxis ? 'right' : 'left'); lines.clipEdge(true).duration(0); lines2.interactive(false); // We don't want any points emitted for the focus chart's scatter graph. lines2.pointActive(function(d) { return false; }); x2Axis.orient('bottom').tickPadding(5); y2Axis.orient(rightAlignYAxis ? 'right' : 'left'); tooltip.valueFormatter(function(d, i) { return yAxis.tickFormat()(d, i); }).headerFormatter(function(d, i) { return xAxis.tickFormat()(d, i); }); interactiveLayer.tooltip.valueFormatter(function(d, i) { return yAxis.tickFormat()(d, i); }).headerFormatter(function(d, i) { return xAxis.tickFormat()(d, i); }); //============================================================ // Private Variables //------------------------------------------------------------ var renderWatch = nv.utils.renderWatch(dispatch, duration); var stateGetter = function(data) { return function(){ return { active: data.map(function(d) { return !d.disabled; }) }; }; }; var stateSetter = function(data) { return function(state) { if (state.active !== undefined) data.forEach(function(series,i) { series.disabled = !state.active[i]; }); }; }; function chart(selection) { renderWatch.reset(); renderWatch.models(lines); renderWatch.models(lines2); if (showXAxis) renderWatch.models(xAxis); if (showYAxis) renderWatch.models(yAxis); if (focusShowAxisX) renderWatch.models(x2Axis); if (focusShowAxisY) renderWatch.models(y2Axis); selection.each(function(data) { var container = d3.select(this); nv.utils.initSVG(container); var availableWidth = nv.utils.availableWidth(width, container, margin), availableHeight1 = nv.utils.availableHeight(height, container, margin) - (focusEnable ? focusHeight : 0), availableHeight2 = focusHeight - margin2.top - margin2.bottom; chart.update = function() { if( duration === 0 ) { container.call( chart ); } else { container.transition().duration(duration).call(chart); } }; chart.container = this; state .setter(stateSetter(data), chart.update) .getter(stateGetter(data)) .update(); // DEPRECATED set state.disableddisabled state.disabled = data.map(function(d) { return !!d.disabled; }); if (!defaultState) { var key; defaultState = {}; for (key in state) { if (state[key] instanceof Array) defaultState[key] = state[key].slice(0); else defaultState[key] = state[key]; } } // Display noData message if there's nothing to show. if (!data || !data.length || !data.filter(function(d) { return d.values.length; }).length) { nv.utils.noData(chart, container); return chart; } else { container.selectAll('.nv-noData').remove(); } // Setup Scales x = lines.xScale(); y = lines.yScale(); x2 = lines2.xScale(); y2 = lines2.yScale(); // Setup containers and skeleton of chart var wrap = container.selectAll('g.nv-wrap.nv-lineChart').data([data]); var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineChart').append('g'); var g = wrap.select('g'); gEnter.append('g').attr('class', 'nv-legendWrap'); var focusEnter = gEnter.append('g').attr('class', 'nv-focus'); focusEnter.append('g').attr('class', 'nv-background').append('rect'); focusEnter.append('g').attr('class', 'nv-x nv-axis'); focusEnter.append('g').attr('class', 'nv-y nv-axis'); focusEnter.append('g').attr('class', 'nv-linesWrap'); focusEnter.append('g').attr('class', 'nv-interactive'); var contextEnter = gEnter.append('g').attr('class', 'nv-context'); contextEnter.append('g').attr('class', 'nv-background').append('rect'); contextEnter.append('g').attr('class', 'nv-x nv-axis'); contextEnter.append('g').attr('class', 'nv-y nv-axis'); contextEnter.append('g').attr('class', 'nv-linesWrap'); contextEnter.append('g').attr('class', 'nv-brushBackground'); contextEnter.append('g').attr('class', 'nv-x nv-brush'); // Legend if (showLegend) { legend.width(availableWidth); g.select('.nv-legendWrap') .datum(data) .call(legend); if ( margin.top != legend.height()) { margin.top = legend.height(); availableHeight1 = nv.utils.availableHeight(height, container, margin) - (focusEnable ? focusHeight : 0); } wrap.select('.nv-legendWrap') .attr('transform', 'translate(0,' + (-margin.top) +')'); } wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); if (rightAlignYAxis) { g.select(".nv-y.nv-axis") .attr("transform", "translate(" + availableWidth + ",0)"); } //Set up interactive layer if (useInteractiveGuideline) { interactiveLayer .width(availableWidth) .height(availableHeight1) .margin({left:margin.left, top:margin.top}) .svgContainer(container) .xScale(x); wrap.select(".nv-interactive").call(interactiveLayer); } g.select('.nv-focus .nv-background rect') .attr('width', availableWidth) .attr('height', availableHeight1); lines .width(availableWidth) .height(availableHeight1) .color(data.map(function(d,i) { return d.color || color(d, i); }).filter(function(d,i) { return !data[i].disabled; })); var linesWrap = g.select('.nv-linesWrap') .datum(data.filter(function(d) { return !d.disabled; })); // Setup Main (Focus) Axes if (showXAxis) { xAxis .scale(x) ._ticks(nv.utils.calcTicksX(availableWidth/100, data) ) .tickSize(-availableHeight1, 0); } if (showYAxis) { yAxis .scale(y) ._ticks( nv.utils.calcTicksY(availableHeight1/36, data) ) .tickSize( -availableWidth, 0); } //============================================================ // Update Axes //============================================================ function updateXAxis() { if(showXAxis) { g.select('.nv-focus .nv-x.nv-axis') .transition() .duration(duration) .call(xAxis) ; } } function updateYAxis() { if(showYAxis) { g.select('.nv-focus .nv-y.nv-axis') .transition() .duration(duration) .call(yAxis) ; } } g.select('.nv-focus .nv-x.nv-axis') .attr('transform', 'translate(0,' + availableHeight1 + ')'); if( !focusEnable ) { linesWrap.call(lines); updateXAxis(); updateYAxis(); } else { lines2 .defined(lines.defined()) .width(availableWidth) .height(availableHeight2) .color(data.map(function(d,i) { return d.color || color(d, i); }).filter(function(d,i) { return !data[i].disabled; })); g.select('.nv-context') .attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')') .style('display', focusEnable ? 'initial' : 'none') ; var contextLinesWrap = g.select('.nv-context .nv-linesWrap') .datum(data.filter(function(d) { return !d.disabled; })) ; d3.transition(contextLinesWrap).call(lines2); // Setup Brush brush .x(x2) .on('brush', function() { onBrush(); }) .on('brushend', function() { dispatch.brushend({brush: brush}); }); if (brushExtent) brush.extent(brushExtent); var brushBG = g.select('.nv-brushBackground').selectAll('g') .data([brushExtent || brush.extent()]); var brushBGenter = brushBG.enter() .append('g'); brushBGenter.append('rect') .attr('class', 'left') .attr('x', 0) .attr('y', 0) .attr('height', availableHeight2); brushBGenter.append('rect') .attr('class', 'right') .attr('x', 0) .attr('y', 0) .attr('height', availableHeight2); var gBrush = g.select('.nv-x.nv-brush') .call(brush); gBrush.selectAll('rect') .attr('height', availableHeight2); gBrush.selectAll('.resize').append('path').attr('d', resizePath); onBrush(); g.select('.nv-context .nv-background rect') .attr('width', availableWidth) .attr('height', availableHeight2); // Setup Secondary (Context) Axes if (focusShowAxisX) { x2Axis .scale(x2) ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) .tickSize(-availableHeight2, 0); g.select('.nv-context .nv-x.nv-axis') .attr('transform', 'translate(0,' + y2.range()[0] + ')'); d3.transition(g.select('.nv-context .nv-x.nv-axis')) .call(x2Axis); } if (focusShowAxisY) { y2Axis .scale(y2) ._ticks( nv.utils.calcTicksY(availableHeight2/36, data) ) .tickSize( -availableWidth, 0); d3.transition(g.select('.nv-context .nv-y.nv-axis')) .call(y2Axis); } g.select('.nv-context .nv-x.nv-axis') .attr('transform', 'translate(0,' + y2.range()[0] + ')'); } //============================================================ // Event Handling/Dispatching (in chart's scope) //------------------------------------------------------------ legend.dispatch.on('stateChange', function(newState) { for (var key in newState) state[key] = newState[key]; dispatch.stateChange(state); chart.update(); }); interactiveLayer.dispatch.on('elementMousemove', function(e) { lines.clearHighlights(); var singlePoint, pointIndex, pointXLocation, allData = []; data .filter(function(series, i) { series.seriesIndex = i; return !series.disabled && !series.disableTooltip; }) .forEach(function(series,i) { var extent = focusEnable ? (brush.empty() ? x2.domain() : brush.extent()) : x.domain(); var currentValues = series.values.filter(function(d,i) { return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1]; }); pointIndex = nv.interactiveBisect(currentValues, e.pointXValue, lines.x()); var point = currentValues[pointIndex]; var pointYValue = chart.y()(point, pointIndex); if (pointYValue !== null) { lines.highlightPoint(series.seriesIndex, pointIndex, true); } if (point === undefined) return; if (singlePoint === undefined) singlePoint = point; if (pointXLocation === undefined) pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); allData.push({ key: series.key, value: pointYValue, color: color(series,series.seriesIndex), data: point }); }); //Highlight the tooltip entry based on which point the mouse is closest to. if (allData.length > 2) { var yValue = chart.yScale().invert(e.mouseY); var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]); var threshold = 0.03 * domainExtent; var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value;}),yValue,threshold); if (indexToHighlight !== null) allData[indexToHighlight].highlight = true; } interactiveLayer.tooltip .chartContainer(chart.container.parentNode) .valueFormatter(function(d,i) { return d === null ? "N/A" : yAxis.tickFormat()(d); }) .data({ value: chart.x()( singlePoint,pointIndex ), index: pointIndex, series: allData })(); interactiveLayer.renderGuideLine(pointXLocation); }); interactiveLayer.dispatch.on('elementClick', function(e) { var pointXLocation, allData = []; data.filter(function(series, i) { series.seriesIndex = i; return !series.disabled; }).forEach(function(series) { var pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); var point = series.values[pointIndex]; if (typeof point === 'undefined') return; if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); var yPos = chart.yScale()(chart.y()(point,pointIndex)); allData.push({ point: point, pointIndex: pointIndex, pos: [pointXLocation, yPos], seriesIndex: series.seriesIndex, series: series }); }); lines.dispatch.elementClick(allData); }); interactiveLayer.dispatch.on("elementMouseout",function(e) { lines.clearHighlights(); }); dispatch.on('changeState', function(e) { if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) { data.forEach(function(series,i) { series.disabled = e.disabled[i]; }); state.disabled = e.disabled; } chart.update(); }); //============================================================ // Functions //------------------------------------------------------------ // Taken from crossfilter (http://square.github.com/crossfilter/) function resizePath(d) { var e = +(d == 'e'), x = e ? 1 : -1, y = availableHeight2 / 3; return 'M' + (0.5 * x) + ',' + y + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6) + 'V' + (2 * y - 6) + 'A6,6 0 0 ' + e + ' ' + (0.5 * x) + ',' + (2 * y) + 'Z' + 'M' + (2.5 * x) + ',' + (y + 8) + 'V' + (2 * y - 8) + 'M' + (4.5 * x) + ',' + (y + 8) + 'V' + (2 * y - 8); } function updateBrushBG() { if (!brush.empty()) brush.extent(brushExtent); brushBG .data([brush.empty() ? x2.domain() : brushExtent]) .each(function(d,i) { var leftWidth = x2(d[0]) - x.range()[0], rightWidth = availableWidth - x2(d[1]); d3.select(this).select('.left') .attr('width', leftWidth < 0 ? 0 : leftWidth); d3.select(this).select('.right') .attr('x', x2(d[1])) .attr('width', rightWidth < 0 ? 0 : rightWidth); }); } function onBrush() { brushExtent = brush.empty() ? null : brush.extent(); var extent = brush.empty() ? x2.domain() : brush.extent(); //The brush extent cannot be less than one. If it is, don't update the line chart. if (Math.abs(extent[0] - extent[1]) <= 1) { return; } dispatch.brush({extent: extent, brush: brush}); updateBrushBG(); // Update Main (Focus) var focusLinesWrap = g.select('.nv-focus .nv-linesWrap') .datum( data .filter(function(d) { return !d.disabled; }) .map(function(d,i) { return { key: d.key, area: d.area, classed: d.classed, values: d.values.filter(function(d,i) { return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1]; }), disableTooltip: d.disableTooltip }; }) ); focusLinesWrap.transition().duration(duration).call(lines); // Update Main (Focus) Axes updateXAxis(); updateYAxis(); } }); renderWatch.renderEnd('lineChart immediate'); return chart; } //============================================================ // Event Handling/Dispatching (out of chart's scope) //------------------------------------------------------------ lines.dispatch.on('elementMouseover.tooltip', function(evt) { if(!evt.series.disableTooltip){ tooltip.data(evt).hidden(false); } }); lines.dispatch.on('elementMouseout.tooltip', function(evt) { tooltip.hidden(true); }); //============================================================ // Expose Public Variables //------------------------------------------------------------ // expose chart's sub-components chart.dispatch = dispatch; chart.lines = lines; chart.lines2 = lines2; chart.legend = legend; chart.xAxis = xAxis; chart.x2Axis = x2Axis; chart.yAxis = yAxis; chart.y2Axis = y2Axis; chart.interactiveLayer = interactiveLayer; chart.tooltip = tooltip; chart.dispatch = dispatch; chart.options = nv.utils.optionsFunc.bind(chart); chart._options = Object.create({}, { // simple options, just get/set the necessary values width: {get: function(){return width;}, set: function(_){width=_;}}, height: {get: function(){return height;}, set: function(_){height=_;}}, showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, focusEnable: {get: function(){return focusEnable;}, set: function(_){focusEnable=_;}}, focusHeight: {get: function(){return height2;}, set: function(_){focusHeight=_;}}, focusShowAxisX: {get: function(){return focusShowAxisX;}, set: function(_){focusShowAxisX=_;}}, focusShowAxisY: {get: function(){return focusShowAxisY;}, set: function(_){focusShowAxisY=_;}}, brushExtent: {get: function(){return brushExtent;}, set: function(_){brushExtent=_;}}, defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, noData: {get: function(){return noData;}, set: function(_){noData=_;}}, // options that require extra logic in the setter margin: {get: function(){return margin;}, set: function(_){ margin.top = _.top !== undefined ? _.top : margin.top; margin.right = _.right !== undefined ? _.right : margin.right; margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; margin.left = _.left !== undefined ? _.left : margin.left; }}, duration: {get: function(){return duration;}, set: function(_){ duration = _; renderWatch.reset(duration); lines.duration(duration); xAxis.duration(duration); x2Axis.duration(duration); yAxis.duration(duration); y2Axis.duration(duration); }}, focusMargin: {get: function(){return margin2;}, set: function(_){ margin2.top = _.top !== undefined ? _.top : margin2.top; margin2.right = _.right !== undefined ? _.right : margin2.right; margin2.bottom = _.bottom !== undefined ? _.bottom : margin2.bottom; margin2.left = _.left !== undefined ? _.left : margin2.left; }}, color: {get: function(){return color;}, set: function(_){ color = nv.utils.getColor(_); legend.color(color); lines.color(color); }}, interpolate: {get: function(){return lines.interpolate();}, set: function(_){ lines.interpolate(_); lines2.interpolate(_); }}, xTickFormat: {get: function(){return xAxis.tickFormat();}, set: function(_){ xAxis.tickFormat(_); x2Axis.tickFormat(_); }}, yTickFormat: {get: function(){return yAxis.tickFormat();}, set: function(_){ yAxis.tickFormat(_); y2Axis.tickFormat(_); }}, x: {get: function(){return lines.x();}, set: function(_){ lines.x(_); lines2.x(_); }}, y: {get: function(){return lines.y();}, set: function(_){ lines.y(_); lines2.y(_); }}, rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ rightAlignYAxis = _; yAxis.orient( rightAlignYAxis ? 'right' : 'left'); }}, useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ useInteractiveGuideline = _; if (useInteractiveGuideline) { lines.interactive(false); lines.useVoronoi(false); } }} }); nv.utils.inheritOptions(chart, lines); nv.utils.initOptions(chart); return chart; }; nv.models.lineWithFocusChart = function() { return nv.models.lineChart() .margin({ bottom: 30 }) .focusEnable( true ); };
D3.js Gauge look like Telerik Radial Gauge
Hello I need help to add gray (Minor and Major) graduation lines inside the gauge to capture more precisely the position of the needle. Also if you have any idea how we could put text to Major graduation lines. For my sample I would required 7 Major graduation lines divided by 10 minor separations (to look exactly like the Telerik Gauge). Here is my implementation : http://jsfiddle.net/8svg5/ <html> <head runat="server"> <title></title> </head> <body> <div> <a id="myTooltip" title="This is my message"></a> <div id="svgTarget"></div> </div> <script> $(function () { var gaugeRanges = [ { From: 1.5, To: 2.5, Color: "#8dcb2a" }, { From: 2.5, To: 3.5, Color: "#ffc700" }, { From: 3.5, To: 4.5, Color: "#ff7a00" }, { From: 4.5, To: 6, Color: "#c20000" }]; $("#svgTarget").mttD3Gauge({ data: gaugeRanges }); }); </script> </body> </html> (function ($) { $.fn.mttD3Gauge = function (options) { var settings = $.extend({ width: 300, innerRadius: 130, outterRadius: 145, data: [] }, options); this.create = function () { this.html("<svg class='mtt-svgClock' width='" + settings.width + "' height='" + settings.width + "'></svg>"); var maxLimit = 0; var minLimit = 9999999; var d3DataSource = []; var d3TickSource = []; //Data Genration $.each(settings.data, function (index, value) { d3DataSource.push([value.From, value.To, value.Color]); if (value.To > maxLimit) maxLimit = value.To; if (value.From < minLimit) minLimit = value.From; }); if (minLimit > 0) { d3DataSource.push([0, minLimit, "#d7d7d7"]); } var pi = Math.PI; //Control Genration var vis = d3.select(this.selector + " .mtt-svgClock"); var translate = "translate(" + settings.width / 2 + "," + settings.width / 2 + ")"; var cScale = d3.scale.linear().domain([0, maxLimit]).range([-120 * (pi / 180), 120 * (pi / 180)]); var arc = d3.svg.arc() .innerRadius(settings.innerRadius) .outerRadius(settings.outterRadius) .startAngle(function (d) { return cScale(d[0]); }) .endAngle(function (d) { return cScale(d[1]); }); var tickArc = d3.svg.arc() .innerRadius(settings.innerRadius - 20) .outerRadius(settings.innerRadius - 2) .startAngle(function (d) { return cScale(d[0]); }) .endAngle(function (d) { return cScale(d[1]); }); for (var i = 0; i < 10; i++) { var point = (i * maxLimit) / 10.0; d3TickSource.push([point, point +1, "#d7d7d7"]); } vis.selectAll("path") .data(d3DataSource) .enter() .append("path") .attr("d", arc) .style("fill", function (d) { return d[2]; }) .attr("transform", translate); return this; }; return this.create(); }; }(jQuery)); enter code here Here is the link of the page of what i'm trying to achieve with D3.js http://demos.telerik.com/aspnet-ajax/gauge/examples/types/radialgauge/defaultcs.aspx?#qsf-demo-source Any help will be greatly appreciated!
I finally found the way to add graduation, feel free to use this code <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <script src="Scripts/jquery-1.9.1.js"></script> <script src="Scripts/html5shiv.js"></script> <script src="Scripts/d3.v3.min.js"></script> <script src="Scripts/mtt-D3Gauge.js"></script> </head> <body> <div> <a id="myTooltip" title="This is my message"></a> <div id="svgTarget"></div> </div> <script> $(function () { var gaugeRanges = [ { From: 1.5, To: 2.5, Color: "#8dcb2a" }, { From: 2.5, To: 3.5, Color: "#ffc700" }, { From: 3.5, To: 4.5, Color: "#ff7a00" }, { From: 4.5, To: 6, Color: "#c20000" }]; $("#svgTarget").mttD3Gauge({ data: gaugeRanges }); }); </script> </body> </html> (function ($) { $.fn.mttD3Gauge = function (options) { var vis; var settings = $.extend({ width: 300, innerRadius: 130, outterRadius: 145, majorGraduations: 6, minorGraduations: 10, majorGraduationLenght: 16, minorGraduationLenght: 10, majorGraduationMarginTop: 7, majorGraduationColor: "rgb(234,234,234)", minorGraduationColor:"rgb(234,234,234)", data: [] }, options); this.create = function () { this.html("<svg class='mtt-svgClock' width='" + settings.width + "' height='" + settings.width + "'></svg>"); var maxLimit = 0; var minLimit = 9999999; var d3DataSource = []; //Data Genration $.each(settings.data, function (index, value) { d3DataSource.push([value.From, value.To, value.Color]); if (value.To > maxLimit) maxLimit = value.To; if (value.From < minLimit) minLimit = value.From; }); if (minLimit > 0) { d3DataSource.push([0, minLimit, "#d7d7d7"]); } //Render Gauge Color Area vis = d3.select(this.selector + " .mtt-svgClock"); var translate = "translate(" + settings.width / 2 + "," + settings.width / 2 + ")"; var cScale = d3.scale.linear().domain([0, maxLimit]).range([-120 * (Math.PI / 180), 120 * (Math.PI / 180)]); var arc = d3.svg.arc() .innerRadius(settings.innerRadius) .outerRadius(settings.outterRadius) .startAngle(function (d) { return cScale(d[0]); }) .endAngle(function (d) { return cScale(d[1]); }); vis.selectAll("path") .data(d3DataSource) .enter() .append("path") .attr("d", arc) .style("fill", function (d) { return d[2]; }) .attr("transform", translate); renderMajorGraduations(); return this; }; var renderMinorGraduations = function (majorGraduationsAngles, indexMajor) { var graduationsAngles = []; if (indexMajor > 0) { var minScale = majorGraduationsAngles[indexMajor - 1]; var maxScale = majorGraduationsAngles[indexMajor]; var scaleRange = maxScale - minScale; for (var i = 1; i < settings.minorGraduations; i++) { var scaleValue = minScale + i * scaleRange / settings.minorGraduations; graduationsAngles.push(scaleValue); } var xCenter = settings.width / 2; var yCenter = settings.width / 2; //Render Minor Graduations $.each(graduationsAngles, function (indexMinor, value) { var cos1Adj = Math.round(Math.cos((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop - settings.minorGraduationLenght)); var sin1Adj = Math.round(Math.sin((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop - settings.minorGraduationLenght)); var cos2Adj = Math.round(Math.cos((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop)); var sin2Adj = Math.round(Math.sin((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop)); var x1 = xCenter + cos1Adj; var y1 = yCenter + sin1Adj * -1; var x2 = xCenter + cos2Adj; var y2 = yCenter + sin2Adj * -1; vis.append("svg:line") .attr("x1", x1) .attr("y1", y1) .attr("x2", x2) .attr("y2", y2) .style("stroke", settings.majorGraduationColor); }); } }; var renderMajorGraduations = function () { var scaleRange = 240; var minScale = -120; var graduationsAngles = []; for (var i = 0; i <= settings.majorGraduations; i++) { var scaleValue = minScale + i * scaleRange / settings.majorGraduations; graduationsAngles.push(scaleValue); } var xCenter = settings.width / 2; var yCenter = settings.width / 2; //Render Major Graduations $.each(graduationsAngles, function (index, value) { var cos1Adj = Math.round(Math.cos((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop - settings.majorGraduationLenght)); var sin1Adj = Math.round(Math.sin((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop - settings.majorGraduationLenght)); var cos2Adj = Math.round(Math.cos((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop)); var sin2Adj = Math.round(Math.sin((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop)); var x1 = xCenter + cos1Adj; var y1 = yCenter + sin1Adj * -1; var x2 = xCenter + cos2Adj; var y2 = yCenter + sin2Adj * -1; vis.append("svg:line") .attr("x1", x1) .attr("y1", y1) .attr("x2", x2) .attr("y2", y2) .style("stroke", settings.majorGraduationColor); renderMinorGraduations(graduationsAngles, index); }); }; return this.create(); }; }(jQuery));