Recreating collapsible force layout using d3 v4 - force-layout

I've been trying to create a Collapsible force layout using d3js v4, similar to this one: https://mbostock.github.io/d3/talk/20111116/force-collapsible.html
I've been able to create the layout itself. But not able to update it. Can anyone help?
Here's my js code:
var width = 960,
height = 600;
var root = {
"name": "server1900",
"children": [{
"name": "server913",
"_children": null,
"children": [{
"name": "server948"
}, {
"name": "server946"
}]
}, {
"name": "server912",
"_children": null,
"children": [{
"name": "server984"
}, {
"name": "server983"
}]
}, {
"name": "server911",
"_children": null,
"children": [{
"name": "server999",
"_children": null,
"children": [{
"name": "server992"
}]
}]
}]
};
root = d3.hierarchy(root);
var i = 0;
var transform = d3.zoomIdentity;;
var nodeSvg, linkSvg, simulation, nodeEnter, linkEnter ;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.zoom().scaleExtent([1 / 2, 8]).on("zoom", zoomed))
.append("g")
.attr("transform", "translate(40,0)");
function zoomed() {
svg.attr("transform", d3.event.transform);
}
simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2))
.on("tick", ticked);
update();
function update() {
var nodes = flatten(root);
var links = root.links();
simulation
.nodes(nodes)
simulation.force("link")
.links(links);
linkSvg = svg.selectAll(".link")
.data(links, function(d) { return d.target.id; })
linkSvg.exit().remove();
linkSvg = linkSvg.enter()
.append("line")
.attr("class", "link");
nodeSvg = svg.selectAll(".node")
.data(nodes, function(d) { return d.id; })
nodeSvg.exit().remove();
nodeSvg = nodeSvg.enter()
.append("g")
.attr("class", "node")
.on("click", click)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
nodeSvg.append("circle")
.attr("r", 4 )
.append("title")
.text(function(d) { return d.data.name; })
nodeSvg.append("text")
.attr("dy", 3)
.attr("x", function(d) { return d.children ? -8 : 8; })
.style("text-anchor", function(d) { return d.children ? "end" : "start"; })
.text(function(d) { return d.data.name; });
}
function ticked() {
linkSvg
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
nodeSvg
.attr("transform", function(d) { return "translate(" + d.x + ", " + d.y + ")"; });
}
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
update();
simulation.restart();
} else {
d.children = d._children;
d._children = null;
update();
simulation.restart();
}
}
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart()
simulation.fix(d);
}
function dragged(d) {
simulation.fix(d, d3.event.x, d3.event.y);
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
simulation.unfix(d);
}
function flatten (root) {
// hierarchical data to flat data for force layout
var nodes = [];
function recurse(node) {
if (node.children) node.children.forEach(recurse);
if (!node.id) node.id = ++i;
else ++i;
nodes.push(node);
}
recurse(root);
return nodes;
}
line {
stroke: #666;
}
.node {
pointer-events: all;
}
circle {
stroke: none;
stroke-width: 40px;
}
.node text {
font: 8px sans-serif;
}
<script src="https://d3js.org/d3.v4.0.0-alpha.50.min.js"></script>
Here's my fiddle. https://jsfiddle.net/t4vzg650/4/
Thanks

I forgot to merge old nodes after enter().
link = svg.selectAll(".link").data(links, function(d) { return d.target.id; })
var linkEnter = link.enter().append("line").attr("class", "link");
link = linkEnter.merge(link);
Thanks to Mike Bostock for helping me with this problem. I thought there was an issue with d3 v4, turns out I didn't read changes fully :|
Refer this for more info: https://github.com/d3/d3-force/issues/37
Fixed fiddle: https://jsfiddle.net/t4vzg650/6/

Related

I'm using d3.v3.min.js for showing a data like mindmap structure.I'm having large number of data's so it is very inconvinient to dispaly the data

I have more than 100 data's as a children in a json file,how to show only limited number of data's in chidren node.I have json data with array of children with more than 100data's,i want to show only 10 data's in node and remaining data should be in hide when i expand it should load another data,this should done for every node.Can any one help me out.Here is my code.
And here is my directive:
app.directive('mindMap', function () {
return {
link: function(scope, element) {
var eleW = element[0].clientWidth,
eleH = element[0].clientHeight;
var m = [20,40,20,80],
w = eleW - m[1] - m[3],
h = eleH - m[0] - m[2],
i = 0,
root;
var tree = d3.layout.tree().size([h, w]);
var diagonal = d3.svg.diagonal().projection(function(d) { return [d.y, d.x]; });
var vis = d3.select(element[0]).append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
// Toggle children.
function toggle(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
}
function toggleAll(d) {
if (d.children) {
d.children.forEach(toggleAll);
toggle(d);
}
}
scope.$watch('json' , function(){
if(!(scope.json != null)){
scope.json = {
"name" : "root"
}
}
root = scope.json;
root.x0 = h/2;
root.y0 = 0;
update(root);
scope.root = root;
});
function update(source) {
console.log(source);
var duration = 500;
if(!(source != null)){
return;
}
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
// Normalize for fixed-depth.
var deepest = 0,
generationGutter = w;
nodes.forEach(function(d){
if(deepest < d.depth){
deepest = d.depth;
}
});
generationGutter = Math.floor(w/(deepest+1));
nodes.forEach(function(d) { d.y = d.depth * generationGutter; });
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
console.log(node);
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; });
//inject content to node
InjectNodeContent(nodeEnter);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeUpdate.select("text")
.text(function(d) { return d.name; })
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = vis.selectAll("path.link")
.data(tree.links(nodes), function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("svg:path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
})
.transition()
.duration(duration)
.attr("d", diagonal);
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
function InjectNodeContent (nodeEnter) {
nodeEnter.append("svg:circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; })
.classed("toggleCircle" , true)
.on("click", function(d) {
toggle(d);
update(d);
});
nodeEnter.append("svg:text")
.attr("x", function(d) { return d.children || d._children ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
}
}
}
});
My sample JSON data:
{
"name": "Parent",
"children": [
{
"name": "child1",
"children": [
{"name": "subchild1"},
{"name": "subchild2"}
]
},
{
"name": "child2",
"children": [
{"name": "subchild3"},
{"name": "subchild4"}
]
},
{"name": "subchild5"},
{"name": "subchild6"},
{"name": "subchild7"},
{"name": "subchild8"},
{"name": "subchild9"}
]
}

Why are my SVG foreign object text not showing up?

I am trying to collapse a set of foreign objects so I do that like this.
$scope.render = function(center) {
$scope.direction = $scope.direction ? $scope.direction : "RL";
var nodes = $scope.container.selectAll(".subNode")
.data($scope.node.nodes);
nodes.exit().remove();
$scope.nodeElements = nodes.enter().append("g")
.attr({
class: "subNode",
})
$scope.nodeElements.append("foreignObject")
.attr("width", 300)
.attr("height", 100)
.append("xhtml:body")
.style("font", "14px 'Helvetica Neue'")
.html(function(d) {
return d.label
});
$scope.container.select("rect.mainNode")
.remove();
var mainNode = $scope.container.append("g")
.attr({
x: 0,
y: 0,
class: "mainNode",
})
.on({
click: function(d) {
$scope.open = !$scope.open;
$scope.container.selectAll(".subNode").transition()
.attr({
transform: function(d, i) {
var r = 0;
if ($scope.open) {
r = i * 100 + i * 10 + 110;
}
if ($scope.direction == "RL") {
return "translate(" + r + ", 0)"
} else {
return "translate(0, " + r + ")"
}
}
})
}
})
mainNode.append("foreignObject")
.attr("width", 10)
.attr("height", 10)
.append("xhtml:body")
.style("font", "14px 'Helvetica Neue'")
.html($scope.node.label);
mainNode.selectAll("foreignObject").transition()
.attr({
x: function(d, i) {
return 0
},
y: 0,
height: 100,
width: 300
});
}
When i inspect the DOM everything looks correct but I do not see the text. What am I missing?
Looks like the transform does not move the viewable window. If I add an x/y to the foreign object instead it works.

D3 tween does not work inside angular

I'm working on this example:
http://bl.ocks.org/mbostock/7607535
I wrapped this into a directive. For some reason, the tween method does not get fired.
var transition = d3.transition()
.duration(d3.event.altKey ? 7500 : 750)
.tween("zoom", function(d) {
var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]);
return function(t) { zoomTo(i(t)); };
});
Is tween incompatible with angular ? Any idea where I should start looking ?
I made a small fiddle from the above http://bl.ocks.org/mbostock/7607535.
I have incorporated the d3 svg component via directive and the tween works perfectly.
var app = angular.module('myApp', []);
app.controller('myController', ['$scope', function ($scope) {
$scope.myData = {"name":"flare","children":[{"name":"analytics","children":[{"name":"cluster","children":[{"name":"AgglomerativeCluster","size":3938},{"name":"CommunityStructure","size":3812},{"name":"HierarchicalCluster","size":6714},{"name":"MergeEdge","size":743}]},{"name":"graph","children":[{"name":"BetweennessCentrality","size":3534},{"name":"LinkDistance","size":5731},{"name":"MaxFlowMinCut","size":7840},{"name":"ShortestPaths","size":5914},{"name":"SpanningTree","size":3416}]},{"name":"optimization","children":[{"name":"AspectRatioBanker","size":7074}]}]},{"name":"animate","children":[{"name":"Easing","size":17010},{"name":"FunctionSequence","size":5842},{"name":"interpolate","children":[{"name":"ArrayInterpolator","size":1983},{"name":"ColorInterpolator","size":2047},{"name":"DateInterpolator","size":1375},{"name":"Interpolator","size":8746},{"name":"MatrixInterpolator","size":2202},{"name":"NumberInterpolator","size":1382},{"name":"ObjectInterpolator","size":1629},{"name":"PointInterpolator","size":1675},{"name":"RectangleInterpolator","size":2042}]},{"name":"ISchedulable","size":1041},{"name":"Parallel","size":5176},{"name":"Pause","size":449},{"name":"Scheduler","size":5593},{"name":"Sequence","size":5534},{"name":"Transition","size":9201},{"name":"Transitioner","size":19975},{"name":"TransitionEvent","size":1116},{"name":"Tween","size":6006}]},{"name":"data","children":[{"name":"converters","children":[{"name":"Converters","size":721},{"name":"DelimitedTextConverter","size":4294},{"name":"GraphMLConverter","size":9800},{"name":"IDataConverter","size":1314},{"name":"JSONConverter","size":2220}]},{"name":"DataField","size":1759},{"name":"DataSchema","size":2165},{"name":"DataSet","size":586},{"name":"DataSource","size":3331},{"name":"DataTable","size":772},{"name":"DataUtil","size":3322}]},{"name":"display","children":[{"name":"DirtySprite","size":8833},{"name":"LineSprite","size":1732},{"name":"RectSprite","size":3623},{"name":"TextSprite","size":10066}]},{"name":"flex","children":[{"name":"FlareVis","size":4116}]},{"name":"physics","children":[{"name":"DragForce","size":1082},{"name":"GravityForce","size":1336},{"name":"IForce","size":319},{"name":"NBodyForce","size":10498},{"name":"Particle","size":2822},{"name":"Simulation","size":9983},{"name":"Spring","size":2213},{"name":"SpringForce","size":1681}]},{"name":"query","children":[{"name":"AggregateExpression","size":1616},{"name":"And","size":1027},{"name":"Arithmetic","size":3891},{"name":"Average","size":891},{"name":"BinaryExpression","size":2893},{"name":"Comparison","size":5103},{"name":"CompositeExpression","size":3677},{"name":"Count","size":781},{"name":"DateUtil","size":4141},{"name":"Distinct","size":933},{"name":"Expression","size":5130},{"name":"ExpressionIterator","size":3617},{"name":"Fn","size":3240},{"name":"If","size":2732},{"name":"IsA","size":2039},{"name":"Literal","size":1214},{"name":"Match","size":3748},{"name":"Maximum","size":843},{"name":"methods","children":[{"name":"add","size":593},{"name":"and","size":330},{"name":"average","size":287},{"name":"count","size":277},{"name":"distinct","size":292},{"name":"div","size":595},{"name":"eq","size":594},{"name":"fn","size":460},{"name":"gt","size":603},{"name":"gte","size":625},{"name":"iff","size":748},{"name":"isa","size":461},{"name":"lt","size":597},{"name":"lte","size":619},{"name":"max","size":283},{"name":"min","size":283},{"name":"mod","size":591},{"name":"mul","size":603},{"name":"neq","size":599},{"name":"not","size":386},{"name":"or","size":323},{"name":"orderby","size":307},{"name":"range","size":772},{"name":"select","size":296},{"name":"stddev","size":363},{"name":"sub","size":600},{"name":"sum","size":280},{"name":"update","size":307},{"name":"variance","size":335},{"name":"where","size":299},{"name":"xor","size":354},{"name":"_","size":264}]},{"name":"Minimum","size":843},{"name":"Not","size":1554},{"name":"Or","size":970},{"name":"Query","size":13896},{"name":"Range","size":1594},{"name":"StringUtil","size":4130},{"name":"Sum","size":791},{"name":"Variable","size":1124},{"name":"Variance","size":1876},{"name":"Xor","size":1101}]},{"name":"scale","children":[{"name":"IScaleMap","size":2105},{"name":"LinearScale","size":1316},{"name":"LogScale","size":3151},{"name":"OrdinalScale","size":3770},{"name":"QuantileScale","size":2435},{"name":"QuantitativeScale","size":4839},{"name":"RootScale","size":1756},{"name":"Scale","size":4268},{"name":"ScaleType","size":1821},{"name":"TimeScale","size":5833}]},{"name":"util","children":[{"name":"Arrays","size":8258},{"name":"Colors","size":10001},{"name":"Dates","size":8217},{"name":"Displays","size":12555},{"name":"Filter","size":2324},{"name":"Geometry","size":10993},{"name":"heap","children":[{"name":"FibonacciHeap","size":9354},{"name":"HeapNode","size":1233}]},{"name":"IEvaluable","size":335},{"name":"IPredicate","size":383},{"name":"IValueProxy","size":874},{"name":"math","children":[{"name":"DenseMatrix","size":3165},{"name":"IMatrix","size":2815},{"name":"SparseMatrix","size":3366}]},{"name":"Maths","size":17705},{"name":"Orientation","size":1486},{"name":"palette","children":[{"name":"ColorPalette","size":6367},{"name":"Palette","size":1229},{"name":"ShapePalette","size":2059},{"name":"SizePalette","size":2291}]},{"name":"Property","size":5559},{"name":"Shapes","size":19118},{"name":"Sort","size":6887},{"name":"Stats","size":6557},{"name":"Strings","size":22026}]}]}
}]);
app.directive('packChart', function () {
return {
restrict: 'EA',
link: function (scope, elem, attrs) {
var root = scope.myData;
var margin = 20,
diameter = 960;
var color = d3.scale.linear()
.domain([-1, 5])
.range(["hsl(152,80%,80%)", "hsl(228,30%,40%)"])
.interpolate(d3.interpolateHcl);
var pack = d3.layout.pack()
.padding(2)
.size([diameter - margin, diameter - margin])
.value(function (d) {
return d.size;
})
var svg = d3.select("svg")
.attr("width", diameter)
.attr("height", diameter)
.append("g")
.attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
var focus = root,
nodes = pack.nodes(root),
view;
var circle = svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("class", function (d) {
return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root";
})
.style("fill", function (d) {
return d.children ? color(d.depth) : null;
})
.on("click", function (d) {
if (focus !== d) zoom(d), d3.event.stopPropagation();
});
var text = svg.selectAll("text")
.data(nodes)
.enter().append("text")
.attr("class", "label")
.style("fill-opacity", function (d) {
return d.parent === root ? 1 : 0;
})
.style("display", function (d) {
return d.parent === root ? null : "none";
})
.text(function (d) {
return d.name;
});
var node = svg.selectAll("circle,text");
d3.select("body")
.style("background", color(-1))
.on("click", function () {
zoom(root);
});
zoomTo([root.x, root.y, root.r * 2 + margin]);
function zoom(d) {
var focus0 = focus;
focus = d;
var transition = d3.transition()
.duration(d3.event.altKey ? 7500 : 750)
.tween("zoom", function (d) {
var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]);
return function (t) {
zoomTo(i(t));
};
});
transition.selectAll("text")
.filter(function (d) {
return d.parent === focus || this.style.display === "inline";
})
.style("fill-opacity", function (d) {
return d.parent === focus ? 1 : 0;
})
.each("start", function (d) {
if (d.parent === focus) this.style.display = "inline";
})
.each("end", function (d) {
if (d.parent !== focus) this.style.display = "none";
});
}
function zoomTo(v) {
var k = diameter / v[2];
view = v;
node.attr("transform", function (d) {
return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")";
});
circle.attr("r", function (d) {
return d.r * k;
});
}
}
};
});
.node {
cursor: pointer;
}
.node:hover {
stroke: #000;
stroke-width: 1.5px;
}
.node--leaf {
fill: white;
}
.label {
font: 11px"Helvetica Neue", Helvetica, Arial, sans-serif;
text-anchor: middle;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff, 0 -1px 0 #fff;
}
.label, .node--root, .node--leaf {
pointer-events: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div ng-app='myApp' ng-controller="myController">
<h1>My Chart</h1>
<svg pack-chart></svg>
</div>
Working code here
Hope this helps!
The root of the problem was datejs. Once I removed it, D3 transitions work fine.

nvd3 pie chart when no data and for value zero

I have created a pie chart using nvd3.
Here is my code :
<nvd3-pie-chart
data="examplePieData"
id="exampleId"
showLabels="true"
labelType="value"
x="xPieFunction()"
y="yPieFunction()"
donut="true"
donutRatio=".5"
tooltips="true"
noData="Data aint here"
tooltipcontent="toolTipContentFunction()"
color="pieColorFunction()"
donutLabelsOutside="false">
<svg height="200" style="margin-left: -121px; margin-top: -49px;"></svg>
</nvd3-pie-chart>
and
$scope.examplePieData = [
{
key: "First",
y: 5
},
{
key: "Second",
y: 3
},
{
key: "Third",
y: 1
}
];
$scope.toolTipContentFunction = function(){
return function(key, x, y, e, graph) {
return '<p>' + key +" "+ y.value + '</p>'
}
}
$scope.xPieFunction = function(){
return function(d) {
return d.key;
};
}
$scope.yPieFunction = function(){
return function(d) {
return d.y;
};
}
var pieColorArray = [ '#5EA9DD','#e76060', '#008000'];
$scope.pieColorFunction = function() {
return function(d, i) {
return pieColorArray[i];
};
}
Here I want to display a message when there is no data. I have tried with noDate = "Message" but it is not working. And I want to show pic chart even for y value is zero (y :0). Finally, how to adjust tooltip distance and same color for the tooltip when mouseover on the perticular field in pie chart. Help me. Thank you.
For no data, try with chart.noData() function. For me it is perfectly working,
HTML:
<div id="chart">
<svg></svg>
</div>
Javascript:
var h = 300;
var r = h/2;
var data = [];
var colors = [
'rgb(178, 55, 56)',
'rgb(213, 69, 70)',
'rgb(230, 125, 126)',
'rgb(239, 183, 182)'
];
nv.addGraph(function() {
var chart = nv.models.pieChart()
.x(function(d) { return d.label })
.y(function(d) { return d.value })
.color(colors)
.showLabels(true)
.labelType("percent");
chart.noData("No data");
d3.select("#chart svg")
.datum(data)
.transition().duration(1200)
.call(chart)
;
return chart;
});

How to draw a d3.js line chart using angularjs directives

How to use angular directives to load the d3.js graph using scope json data instead of using graph.html file.I had referred this urlurl.But unable to do it for line chart.
Can anyone please help me out regarding this issue ...
My graph.html:
function getDate(d) {
var dt = new Date(d.date);
dt.setHours(0);
dt.setMinutes(0);
dt.setSeconds(0);
dt.setMilliseconds(0);
return dt;
}
function showData(obj, d) {
var coord = d3.mouse(obj);
var infobox = d3.select(".infobox");
// now we just position the infobox roughly where our mouse is
infobox.style("left", (coord[0] + 100) + "px" );
infobox.style("top", (coord[1] - 175) + "px");
$(".infobox").html(d);
$(".infobox").show();
}
function hideData() {
$(".infobox").hide();
}
var drawChart = function(data) {
// define dimensions of graph
var m = [10, 20, 10, 50]; // margins
var w = 250 - m[1] - m[3]; // width
var h = 100 - m[0] - m[2]; // height
data.sort(function(a, b) {
var d1 = getDate(a);
var d2 = getDate(b);
if (d1 == d2) return 0;
if (d1 > d2) return 1;
return -1;
});
var minDate = getDate(data[0]),
maxDate = getDate(data[data.length-1]);
var x = d3.time.scale().domain([minDate, maxDate]).range([0, w]);
var y = d3.scale.linear().domain([0, d3.max(data, function(d) { return d.trendingValue; } )]).range([h, 0]);
var line = d3.svg.line()
.x(function(d, i) {
return x(getDate(d)); //x(i);
})
.y(function(d) {
return y(d.trendingValue);
});
function xx(e) { return x(getDate(e)); };
function yy(e) { return y(e.trendingValue); };
var graph = d3.select("#chart").append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
var xAxis = d3.svg.axis().scale(x).ticks(d3.time.months, 1).tickSize(-h).tickSubdivide(true);
var yAxisLeft = d3.svg.axis().scale(y).ticks(10).orient("left"); //.tickFormat(formalLabel);
graph
.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("fill", "steelblue")
.attr("r", 5)
.attr("cx", xx)
.attr("cy", yy)
.on("mouseover", function(d) { showData(this, d.trendingValue);})
.on("mouseout", function(){ hideData();});
graph.append("svg:path").attr("d", line(data));
$("#chart").append("<div class='infobox' style='display:none;'>Test</div>");
}
My directive:(which I had tried but unable to draw a graph)
angular.module( 'chart').directive( 'crD3Bars', [
function () {
return {
restrict: 'E',
scope: {
data: '='
},
link: function (scope, element) {
function getDate(d) {
var dt = new Date(d.date);
dt.setHours(0);
dt.setMinutes(0);
dt.setSeconds(0);
dt.setMilliseconds(0);
return dt;
}
function showData(obj, d) {
var coord = d3.mouse(obj);
var infobox = d3.select(".infobox");
// now we just position the infobox roughly where our mouse is
infobox.style("left", (coord[0] + 100) + "px" );
infobox.style("top", (coord[1] - 175) + "px");
$(".infobox").html(d);
$(".infobox").show();
}
function hideData() {
$(".infobox").hide();
}
var drawChart = function(data) {
// define dimensions of graph
var m = [10, 20, 10, 50]; // margins
var w = 250 - m[1] - m[3]; // width
var h = 100 - m[0] - m[2]; // height
data.sort(function(a, b) {
var d1 = getDate(a);
var d2 = getDate(b);
if (d1 == d2) return 0;
if (d1 > d2) return 1;
return -1;
});
var minDate = getDate(data[0]),
maxDate = getDate(data[data.length-1]);
var x = d3.time.scale().domain([minDate, maxDate]).range([0, w]);
var y = d3.scale.linear().domain([0, d3.max(data, function(d) { return d.trendingValue; } )]).range([h, 0]);
var line = d3.svg.line()
.x(function(d, i) {
return x(getDate(d)); //x(i);
})
.y(function(d) {
return y(d.trendingValue);
});
function xx(e) { return x(getDate(e)); };
function yy(e) { return y(e.trendingValue); };
var graph = d3.select("#chart").append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
var xAxis = d3.svg.axis().scale(x).ticks(d3.time.months, 1).tickSize(-h).tickSubdivide(true);
var yAxisLeft = d3.svg.axis().scale(y).ticks(10).orient("left"); //.tickFormat(formalLabel);
graph
.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("fill", "steelblue")
.attr("r", 5)
.attr("cx", xx)
.attr("cy", yy)
.on("mouseover", function(d) { showData(this, d.trendingValue);})
.on("mouseout", function(){ hideData();});
graph.append("svg:path").attr("d", line(data));
$("#graphDiv3").append("<div class='infobox' style='display:none;'>Test</div>");
}
drawchart(data);
}
};
}
]);
Instead of mashing up two blocks of code and hoping it works, I'd recommend you follow some simple angular tutorials to get a better grasp of the basics. Also, some simple debugging would have gone a long way here.
You do not declare your module.
You do not seem to pass in your data anywhere (like in a controller which also doesn't exist).
The function is drawChart, you are calling drawchart
In your directive, you select a div with id of chart, this doesn't exist. Since it's a directive and they act on elements use d3.select(element[0])
All that said once you work through these relatively simple mistakes, you get some working code:
var myAppModule = angular.module('chart', []);
angular.module('chart').controller('chartCtrl', function ($scope) {
$scope.myData = [{
"date": "2015-10-01",
"trendingValue": "244"
},
{
"date": "2015-07-01",
"trendingValue": "0"
},
{
"date": "2015-06-01",
"trendingValue": "117"
},
{
"date": "2015-05-01",
"trendingValue": "5353"
},
{
"date": "2015-04-01",
"trendingValue": "11159"
},
{
"date": "2015-03-01",
"trendingValue": "7511"
},
{
"date": "2015-02-01",
"trendingValue": "6906"
},
{
"date": "2015-01-01",
"trendingValue": "10816"
},
{
"date": "2014-12-01",
"trendingValue": "3481"
},
{
"date": "2014-11-01",
"trendingValue": "1619"
},
{
"date": "2014-10-01",
"trendingValue": "4084"
},
{
"date": "2014-09-01",
"trendingValue": "1114"
}];
});
angular.module('chart').directive('crD3Bars', [
function() {
return {
restrict: 'E',
scope: {
data: '='
},
link: function(scope, element) {
function getDate(d) {
var dt = new Date(d.date);
dt.setHours(0);
dt.setMinutes(0);
dt.setSeconds(0);
dt.setMilliseconds(0);
return dt;
}
function showData(obj, d) {
var coord = d3.mouse(obj);
var infobox = d3.select(".infobox");
// now we just position the infobox roughly where our mouse is
infobox.style("left", (coord[0] + 100) + "px");
infobox.style("top", (coord[1] - 175) + "px");
$(".infobox").html(d);
$(".infobox").show();
}
function hideData() {
$(".infobox").hide();
}
var drawChart = function(data) {
// define dimensions of graph
var m = [10, 20, 10, 50]; // margins
var w = 250 - m[1] - m[3]; // width
var h = 100 - m[0] - m[2]; // height
data.sort(function(a, b) {
var d1 = getDate(a);
var d2 = getDate(b);
if (d1 == d2) return 0;
if (d1 > d2) return 1;
return -1;
});
var minDate = getDate(data[0]),
maxDate = getDate(data[data.length - 1]);
var x = d3.time.scale().domain([minDate, maxDate]).range([0, w]);
var y = d3.scale.linear().domain([0, d3.max(data, function(d) {
return d.trendingValue;
})]).range([h, 0]);
var line = d3.svg.line()
.x(function(d, i) {
return x(getDate(d)); //x(i);
})
.y(function(d) {
return y(d.trendingValue);
});
function xx(e) {
return x(getDate(e));
}
function yy(e) {
return y(e.trendingValue);
}
var graph = d3.select(element[0]).append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
var xAxis = d3.svg.axis().scale(x).ticks(d3.time.months, 1).tickSize(-h).tickSubdivide(true);
var yAxisLeft = d3.svg.axis().scale(y).ticks(10).orient("left"); //.tickFormat(formalLabel);
graph
.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("fill", "steelblue")
.attr("r", 5)
.attr("cx", xx)
.attr("cy", yy)
.on("mouseover", function(d) {
showData(this, d.trendingValue);
})
.on("mouseout", function() {
hideData();
});
graph.append("svg:path").attr("d", line(data));
$("#graphDiv3").append("<div class='infobox' style='display:none;'>Test</div>");
};
drawChart(scope.data);
}
};
}
]);
<!DOCTYPE html>
<html ng-app="chart">
<head>
<script data-require="angular.js#1.4.8" data-semver="1.4.8" src="https://code.angularjs.org/1.4.8/angular.js"></script>
<script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<script data-require="jquery#2.1.4" data-semver="2.1.4" src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script src="script.js"></script>
</head>
<body>
<div id="graphDiv3" ng-controller="chartCtrl">
<cr-d3-bars data="myData"></cr-d3-bars>
</div>
</body>
</html>

Resources