React—catch scroll wheel, but ignore scrollbar - reactjs

I'm trying to create a scroll-in-viewport-height-increments function and I'm realizing that I only want it to apply to the mousewheel.
Suggestions on how to do this?
Extra credit if you can tell me why my handleScroll function repeats over and over after a single scroll action.
FIDDLE:
componentDidMount() {
window.addEventListener('scroll', this.handleScroll)
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll)
}
handleScroll(e) {
var didScroll;
var delta = 71;
clearTimeout($.data(this, 'scrollTimer'));
$.data(this, 'scrollTimer', setTimeout(() => {
didScroll = true;
if (didScroll) {
var vh = $(window).height();
hasScrolled(vh);
didScroll = false;
}
}, 40));
function hasScrolled(vh) {
var st = $('body').scrollTop();
var scrolldown = st + vh;
var scrollup = st - vh;
if (Math.abs(lastScrollTop - st) <= delta)
return;
if (st > lastScrollTop && st > 70) {
console.log('scrolltop: ' + st + ', viewport height: ' + vh + ', scrolltop DOWN: ' + scrolldown);
$('body').animate({
scrollTop: scrolldown
}, 300, 'swing');
} else {
console.log('scrolltop: ' + st + ', viewport height: ' + vh + ', scrolltop UP: ' + scrollup);
$('body').animate({
scrollTop: scrollup
}, 300, 'swing');
}
lastScrollTop = st;
}
}

Related

How to implement D3 code into a react project

I'm trying to implement this D3 code into an empty react project but the graphic is not showing on the browser. I've tried this below code. I also installed D3 version 3 using npm i d3#3
When I just try implement using vanilla html and vanilla JS, it still doesn't work on the local browser. I'm not sure why it's not working. The author's deployed project seem to work well.
import React from "react";
import * as d3 from "d3";
class Aroma extends React.Component {
componentDidMount(){
var margin = {top: 650, right: 650, bottom: 650, left: 650},
radius = Math.min(margin.top, margin.right, margin.bottom, margin.left) - 168;
function filter_min_arc_size_text(d, i) {return (d.dx*d.depth*radius/1)>14};
var hue = d3.scale.category10();
var luminance = d3.scale.sqrt()
.domain([0, 1e6])
.clamp(true)
.range([80, 20]);
var svg = d3.select("body").append("svg")
.attr("width", margin.left + margin.right)
.attr("height", margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var partition = d3.layout.partition()
.sort(function(a, b) { return d3.ascending(a.name, b.name); })
.size([2 * Math.PI, radius]);
var arc = d3.svg.arc()
.startAngle(function(d) { return d.x; })
.endAngle(function(d) { return d.x + d.dx - .01 / (d.depth + .5); })
.innerRadius(function(d) { return (radius + 6) / 3 * d.depth; })
.outerRadius(function(d) { return (radius + 6) / 3 * (d.depth + 1.) - 1; });
svg.append("image")
.attr("xlink:href", "images/grapes.png")
.attr("x", -650)
.attr("y", -650);
//Tooltip description
var tooltip = d3.select("body")
.append("div")
.attr("id", "tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("opacity", 0);
function format_number(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function format_description(d) {
var description = d.description;
return '<b>' + d.name + '</b></br>'+ d.description + '<br> (' + format_number(d.value) + ')';
}
function computeTextRotation(d) {
var rotation = (d.x + d.dx / 2) * 180 / Math.PI - 90;
return {
global: rotation,
correction: rotation > 90 ? 180 : 0
};
}
function isRotated(d) {
var rotation = (d.x + d.dx / 2) * 180 / Math.PI - 90;
return rotation > 90 ? true : false
}
function mouseOverArc(d) {
d3.select(this).attr("stroke","black")
tooltip.html(format_description(d));
return tooltip.transition()
.duration(50)
.style("opacity", 0.9);
}
function mouseOutArc(){
d3.select(this).attr("stroke","")
return tooltip.style("opacity", 0);
}
function mouseMoveArc (d) {
return tooltip
.style("top", (d3.event.pageY-10)+"px")
.style("left", (d3.event.pageX+10)+"px");
}
var root_ = null;
d3.json("data/davis-aroma-wheel.json", function(error, root) {
if (error) return console.warn(error);
// Compute the initial layout on the entire tree to sum sizes.
// Also compute the full name and fill color for each node,
// and stash the children so they can be restored as we descend.
partition
.value(function(d) { return d.size; })
.nodes(root)
.forEach(function(d) {
d._children = d.children;
d.sum = d.value;
d.key = key(d);
d.fill = fill(d);
});
// Now redefine the value function to use the previously-computed sum.
partition
.children(function(d, depth) { return depth < 3 ? d._children : null; })
.value(function(d) { return d.sum; });
var center = svg.append("circle")
.attr("r", radius / 3)
.on("click", zoomOut);
center.append("title")
.text("Zoom Out");
var partitioned_data = partition.nodes(root).slice(1)
var path = svg.selectAll("path")
.data(partitioned_data)
.enter().append("path")
.attr("d", arc)
.style("fill", function(d) { return d.fill; })
.each(function(d) { this._current = updateArc(d); })
.on("click", zoomIn)
.on("mouseover", mouseOverArc)
.on("mousemove", mouseMoveArc)
.on("mouseout", mouseOutArc);
var texts = svg.selectAll("text")
.data(partitioned_data)
.enter().append("text")
.filter(filter_min_arc_size_text)
.attr("transform", function(d)
{
var r = computeTextRotation(d);
return "rotate(" + r.global + ")"
+ "translate(" + radius / 3. * d.depth + ")"
+ "rotate(" + -r.correction + ")";
})
.style("font-weight", "bold")
.style("text-anchor", "middle")
.attr("dx", function(d) {return isRotated(d) ? "-85" : "85"}) //margin
.attr("dy", ".35em") // vertical-align
.on("click", zoomIn)
.text(function(d,i) {return d.name})
function zoomIn(p) {
if (p.depth > 1) p = p.parent;
if (!p.children) return;
zoom(p, p);
}
function zoomOut(p) {
if (!p.parent) return;
zoom(p.parent, p);
}
// Zoom to the specified new root.
function zoom(root, p) {
if (document.documentElement.__transition__) return;
// Rescale outside angles to match the new layout.
var enterArc,
exitArc,
outsideAngle = d3.scale.linear().domain([0, 2 * Math.PI]);
function insideArc(d) {
return p.key > d.key
? {depth: d.depth - 1, x: 0, dx: 0} : p.key < d.key
? {depth: d.depth - 1, x: 2 * Math.PI, dx: 0}
: {depth: 0, x: 0, dx: 2 * Math.PI};
}
function outsideArc(d) {
return {depth: d.depth + 1, x: outsideAngle(d.x), dx: outsideAngle(d.x + d.dx) - outsideAngle(d.x)};
}
center.datum(root);
// When zooming in, arcs enter from the outside and exit to the inside.
// Entering outside arcs start from the old layout.
//commented //if (root === p) enterArc = outsideArc, exitArc = insideArc, outsideAngle.range([p.x, p.x + p.dx]);
var new_data=partition.nodes(root).slice(1)
path = path.data(new_data, function(d) { return d.key; });
// When zooming out, arcs enter from the inside and exit to the outside.
// Exiting outside arcs transition to the new layout.
//commented// if (root !== p) enterArc = insideArc, exitArc = outsideArc, outsideAngle.range([p.x, p.x + p.dx]);
d3.transition().duration(d3.event.altKey ? 7500 : 750).each(function() {
path.exit().transition()
.style("fill-opacity", function(d) { return d.depth === 1 + (root === p) ? 1 : 0; })
.attrTween("d", function(d) { return arcTween.call(this, exitArc(d)); })
.remove();
path.enter().append("path")
.style("fill-opacity", function(d) { return d.depth === 2 - (root === p) ? 1 : 0; })
.style("fill", function(d) { return d.fill; })
.on("click", zoomIn)
.on("mouseover", mouseOverArc)
.on("mousemove", mouseMoveArc)
.on("mouseout", mouseOutArc)
.each(function(d) { this._current = enterArc(d); });
path.transition()
.style("fill-opacity", 1)
.attrTween("d", function(d) { return arcTween.call(this, updateArc(d)); });
});
texts = texts.data(new_data, function(d) { return d.key; })
texts.exit()
.remove()
texts.enter()
.append("text")
texts.style("opacity", 0)
.attr("transform", function(d) {
var r = computeTextRotation(d);
return "rotate(" + r.global + ")"
+ "translate(" + radius / 3 * d.depth + ",0)"
+ "rotate(" + -r.correction + ")";
})
.style("font-weight", "bold")
.style("text-anchor", "middle")
.attr("dx", function(d) {return isRotated(d) ? "-85" : "85"}) //margin
.attr("dy", ".35em") // vertical-align
.filter(filter_min_arc_size_text)
.on("click", zoomIn)
.text(function(d,i) {return d.name})
.transition().delay(750).style("opacity", 1)
}
});
function key(d) {
var k = [], p = d;
//while (p.depth) k.push(p.name), p = p.parent;
return k.reverse().join(".");
}
function fill(d) {
var p = d;
while (p.depth > 1) p = p.parent;
var c = d3.lab(hue(p.name));
c.l = luminance(d.sum);
return c;
}
function arcTween(b) {
var i = d3.interpolate(this._current, b);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
function updateArc(d) {
return {depth: d.depth, x: d.x, dx: d.dx};
}
d3.select(this.frameElement).style("height", margin.top + margin.bottom + "px");
}
render(){
return <p id="aroma" />;
}
}
export default Aroma;
I emailed the original D3 repo author and he kindly got back to me, mentioning that there's an error with d3 version 3, that it needs longer investigation. He sent me all the resources that he used to build his project 3 years ago.
So I simply decided to follow this action.
Zoomable sunburst chart shows only two layers of the hierarchy at a time in React JS

Using FusionCharts with Ext JS

I am thinking about using FusionCharts in an application entirely build with Ext JS so far.
However, I don't believe there's a specific recommended implementation or connector to easily add FusionCharts to an Ext JS app. There are various examples online of others adding the charts within an Ext JS app though:
http://jsfiddle.net/fusioncharts/xujmxjcb/
http://jsfiddle.net/fusioncharts/5j8s7g68/
https://www.sencha.com/forum/showthread.php?218834-How-to-integrate-fusion-charts-with-Extjs4&p=830921&viewfull=1#post830921
The last one discusses a way to create an Ext JS class for FusionCharts that "wraps" some of the charting functionality within a proper class:
/* * ?????? : var testdata = { part : { 'Jul 01' : 2000, 'Aug 02' : 2400, 'Sep 03' : 2000, 'Oct 04' :
* "", 'Dec 05' : null }, zoo : { 'Jul 01' : 4000, 'Aug 02' : 3400, // 'Sep 03' : 3000, // 'Oct 04' :
* 5200, 'Dec 05' : 4210 }, hotel : { // 'Jul 01' : 6000, 'Aug 02' : 6400, // 'Sep 03' : 7000, 'Oct
* 04' : 8200, 'Dec 05' : 8100 } }; // this.setChartData(testdata); ????????????
*/
/**
* ????
* #class Ext.ux.MSLineChart
* #extends Ext.Panel
* #cgf initData : Object ??????.
* #cgf DwrAction : DWR???? ??????.
* #cgf baseLoadParam : Object DWR???????.
* #cgf autoShowChart : boolean ??(true) ??????????.
* #function loadData() : ??DWR????,????.
* #cgf imageType ???? : MSColumn2D,MSColumn3D,MSLine,MSArea,MSBar2D,MSBar3D StackedColumn2D,
* StackedColumn3D,StackedArea2D,StackedBar2D,StackedBar2D,StackedBar3D
*/
Ext.ux.FusionChart = Ext.extend(Ext.Panel, {
width : 1000,
height : 600,
border : false,
layout : 'fit',
autoShowChart : true,
animationflex : true,
imageType : 'MSLine',
constructor : function(config) {
Ext.apply(this, config);
this.isLineChart = true; // ??????????
var chartDom = Ext.core.DomHelper.append(document.body, {
id : 'ux-fc-' + ++Ext.AbstractComponent.AUTO_ID,
tag : 'div',
cls : 'x-hidden',
style : 'z-index:-1;width:100%;height:100%'
});
this.chart = new FusionCharts(WEBPATH + '/common/fc/' + this.imageType + '.swf', chartDom.id, '100%', "100%", "0",
"1", null);
this.chart.addParam("wmode", "transparent");// ???,????EXT
if (this.initData) {
this.setChartData(this.initData);
} else if (this.DwrAction && this.autoShowChart === true) {
this.loadData(this.baseLoadParam);
}
this.contentEl = this.chart.getAttribute('id');
Ext.ux.FusionChart.superclass.constructor.call(this);
this.on('render', this.renderPanel, this);
},
renderPanel : function() {
},
/** ??DWR??????. */
loadData : function(param) {
param = param || {};
Ext.applyIf(param, this.baseLoadParam);
var setChartData = Ext.bind(this.setChartData, this);
this.DwrAction(param, setChartData);
},
// ??????XML???render chart
setChartData : function(data) {
var animation = this.animationflex == true ? 1 : 0;
var DataXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<chart animation =\"" + animation
+ "\" baseFont=\"??\" baseFontSize=\"12\">";
var valuePartXML = "", trendlinesXML = "";
var xNameArray = [];
if (data['trendlines']) { // ???(??:??,???), ????? : {?:??}
trendlinesXML = "<trendlines> ";
for (var key in data['trendlines']) {
trendlinesXML += "<line startValue='" + key + "' color='" + data['trendlines'][key].replace('#', '')
+ "' displayValue='" + key + "' showOnTop='1' />";
}
trendlinesXML += "</trendlines>";
delete data['trendlines'];
}
DataXML += "<categories>"
for (var key in data) {
if (key.length > 0) {
var record = data[key];
for (var xName in record) {
/* xNameArray.indexOf(xName) == -1 && */
if (xName && String(xName).length > 0) {
DataXML += "<category label=\"" + xName + "\"/>"; // x???
xNameArray.push(xName);
}
}
break; // ????, ???????????. (???????)
}
}
DataXML += "</categories>";
for (var key in data) { // ??
if (key.length > 0) {
var record = data[key];
valuePartXML += "<dataset seriesName=\"" + key + "\">";
for (var i = 0; i < xNameArray.length; i++) {
var xName = xNameArray[i];
if (record[xName] && String(record[xName]).length > 0) {
valuePartXML += "<set value=\"" + record[xName] + "\"/>"; // x???
} else if (this.isLineChart == true) {
record[xName] = this.getEstimated(xName, record, xNameArray);
valuePartXML += "<set showValue =\"0\" toolText=\" \" displayValue=\" \" value=\"" + record[xName] + "\"/>"; // x???
}
}
valuePartXML += "</dataset>";
}
}
DataXML += valuePartXML + trendlinesXML;
DataXML += "</chart>"
this.chart.setDataXML(DataXML);
this.chart.show(); // render
},
/** line????????,?????. */
getEstimated : function(xName, record, xNameArray) {
var front = null;
var back = null;
var space = 2;
for (var i = xNameArray.indexOf(xName) - 1; i > -1; i--) {
var currUp = record[xNameArray[i]];
if (currUp != null && String(currUp).length > 0) {
front = Number(currUp);
break;
}
space++;
}
for (var i = xNameArray.indexOf(xName) + 1; i < xNameArray.length; i++) {
var currDown = record[xNameArray[i]];
if (currDown != null && String(currDown).length > 0) {
back = Number(currDown);
break;
}
space++;
}
if (front == null || back == null) {
return null;
} else {
return (back - front) / space + front;
}
}
})
What is the best way to proceed and what are the advantages/disadvantages?
Any help is greatly appreciated and sorry for the rookie question!
Best
/R

Meaning of hyphen in Angular tags

I found a bit of code on Plunker which I don't understand. It's a word cloud where the cloud is added to the page with:
<tang-cloud words="words" on-click="test(word)" width="500" height="500"></tang-cloud>
This is some how picked up by Angular. What I don't understand is I can find no references to "tang-cloud" in the rest of the code. Various "tangcloud" but nothing with a hyphen.
I'm totally new to Angular, I've stumbled across another case where this seems to happen, but all the tutorial cases I've seen would have used "tangcloud". If I remove the hyphen it stops working, so I must just be missing something simple.
Thank you
It's a directive. Since HTML is case-insensitive, angular converts the tangCloud directive to tang-cloud to be readable by HTML.
The tangCloud directive in tangCloud.js is where you'll find the code for that.
Edit: Just to follow up, you see the bit that says restrict: 'E'? That tells angular that you can use the directive as a custom element. When you make a directive camelcase, like tangCloud, angular will automatically convert it to tang-cloud.
.directive('tangCloud', ['$interpolate', '$compile', '$timeout', function ($interpolate, $compile, $timeout) {
var directive = {
restrict: 'E',
scope: {
width: '=',
height: '=',
words: '=',
onClick: '&',
spin: '='
},
template: function (tElement, tAttrs) {
var isClickable = angular.isDefined(tAttrs.onClick);
var clickAttr = isClickable ? 'ng-click="onClick({word : entry.word, id : entry.id})"' : '';
return "<div class='tangcloud'>" +
"<span ng-repeat='entry in words'" + clickAttr + ">{{entry.word}}</span>" +
"</div>";
},
compile: function (elem) {
elem.children().children()
.addClass('tangcloud-item-' + $interpolate.startSymbol() + 'entry.size' + $interpolate.endSymbol())
.addClass('tangcloud-item-hidden');
return function (scope, elem) {
var centerX = scope.width / 2;
var centerY = scope.height / 2;
var outOfBoundsCount = 0;
var takenSpots = [];
if (scope.words) {
scope.words = shuffleWords(scope.words);
determineWordPositions();
}
function shuffleWords(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
function determineWordPositions() {
$timeout(function () {
var trendSpans = elem.children().eq(0).children();
var length = trendSpans.length;
for (var i = 0; i < length; i++) {
setWordSpanPosition(trendSpans.eq(i));
}
});
}
function setWordSpanPosition(span) {
var height = parseInt(window.getComputedStyle(span[0]).lineHeight, 10);
var width = span[0].offsetWidth;
var spot = setupDefaultSpot(width, height);
var angleMultiplier = 0;
while (spotNotUsable(spot) && outOfBoundsCount < 50) {
spot = moveSpotOnSpiral(spot, angleMultiplier);
angleMultiplier += 1;
}
if (outOfBoundsCount < 50) {
takenSpots.push(spot);
addSpanPositionStyling(span, spot.startX, spot.startY);
}
outOfBoundsCount = 0;
}
function setupDefaultSpot(width, height) {
return {
width: width,
height: height,
startX: centerX - width / 2,
startY: centerY - height / 2,
endX: centerX + width / 2,
endY: centerY + height / 2
};
}
function moveSpotOnSpiral(spot, angleMultiplier) {
var angle = angleMultiplier * 0.1;
spot.startX = centerX + (1.5 * angle) * Math.cos(angle) - (spot.width / 2);
spot.startY = centerY + angle * Math.sin(angle) - (spot.height / 2);
spot.endX = spot.startX + spot.width;
spot.endY = spot.startY + spot.height;
return spot;
}
function spotNotUsable(spot) {
var borders = {
left: centerX - scope.width / 2,
right: centerX + scope.width / 2,
bottom: centerY - scope.height / 2,
top: centerY + scope.height / 2
};
for (var i = 0; i < takenSpots.length; i++) {
if (spotOutOfBounds(spot, borders) || collisionDetected(spot, takenSpots[i])) return true;
}
return false;
}
function spotOutOfBounds(spot, borders) {
if (spot.startX < borders.left ||
spot.endX > borders.right ||
spot.startY < borders.bottom ||
spot.endY > borders.top) {
outOfBoundsCount++;
return true;
} else {
return false;
}
}
function collisionDetected(spot, takenSpot) {
if (spot.startX > takenSpot.endX || spot.endX < takenSpot.startX) {
return false;
}
return !(spot.startY > takenSpot.endY || spot.endY < takenSpot.startY);
}
function addSpanPositionStyling(span, startX, startY) {
var style = "position: absolute; left:" + startX + "px; top: " + startY + "px;";
span.attr("style", style);
span.removeClass("tangcloud-item-hidden");
}
};
}
};
return directive;
}]);
The tang-cloud directive is defined as tangCloud - take this example from the angular docs for directive
app.js
.directive('myCustomer', function() {
return {
template: 'Name: {{customer.name}} Address: {{customer.address}}'
};
});
index.html
<div ng-controller="Controller">
<div my-customer></div>
</div>
See the Normalization section in this part of the docs. Try searching 'tangCloud'

Trying to create D3 + AngularJS Bar Chart

I would like to create a D3 Bar chart with angularjs. This is my directive, and currently I am having a couple of problems.
The chart is not appended to the directives div, but to html tag
Chart is appended multiple times, even though when watch is called, we only log one append
When loggin d3.select(jqElm[0]), it outputs the directives element
What am I doing wrong?
(function (angular, d3) {
'use strict';
var isDef = angular.isDefined,
aExtend = angular.extend,
aCopy = angular.copy,
isArray = angular.isArray,
isObject = angular.isObject,
aElement = angular.element,
isEqual = angular.equals;
angular.module('Widgets.Module')
.factory('ConstructorD3Bar', Constructor)
.directive('tmD3Bar', Directive);
Constructor.$inject = [
'Common'
];
Directive.$inject = [
'Common',
'ConstructorD3Bar'
];
function Constructor(Common) {
var cgenerator = Common.Generator;
function D3Bar(attrs) {
this._setProps(attrs);
}
D3Bar.prototype = {
_setProps: function (p) {
p = p || {};
this.id = isDef(p.id) ? p.id : cgenerator.id;
this.theme = isDef(p.theme) ? p.theme : 'D3Bar';
this.message = isDef(p.message) ? p.message : 'D3Bar';
this.data = isDef(p.data) ? p.data : [];
this.format = isDef(p.format) ? p.format : null;
this.tsv = isDef(p.tsv) ? p.tsv : null;
this.csv = isDef(p.csv) ? p.csv : null;
this.margin = isDef(p.margin) ? p.margin : { top: 0, bottom: 0, left: 0, right: 0};
this.boxWidth = isDef(p.boxWidth) ? p.boxWidth : Common.$window.innerWidth;
this.boxHeight = isDef(p.boxHeight) ? p.boxHeight : Common.$window.innerHeight;
this.width = isDef(p.width) ? p.width : Common.$window.innerWidth;
this.height = isDef(p.height) ? p.height : Common.$window.innerHeight;
this.init();
},
init: function () {
var that = this;
if (that.tsv !== null) {
d3.tsv(that.tsv, function (err, data) {
if (isDef(err) && err && err.status) {
switch (err.status) {
case 404:
return;
}
}
that.data = data;
});
}
},
toString: function () {
return this;
}
};
return {
create: function (props) {
return new D3Bar(props);
}
};
}
function Directive(
Common,
ConstructorD3Bar
) {
var directive = {
templateUrl: 'widgets/d3-charts/bar/bar.tpl.html',
controller: ctrl,
compile: compile,
scope: {
attrs: '=?'
},
replace: true,
restrict: 'AC'
};
return directive;
function compile(tElement, tAttrs) {
return {
pre: function (scope, jqElm, attr) {
scope.initWidget = function () {
if (!isDef(scope.attrs) || scope.attrs === null) {
scope.attrs = ConstructorD3Bar.create({});
}
var margin = scope.attrs.margin,
width = scope.attrs.boxWidth - margin.left - margin.right,
height = scope.attrs.boxHeight - margin.top - margin.bottom;
scope.attrs.width = width;
scope.attrs.height = height;
var formatPercent = d3.format('.0%');
scope.attrs.x = d3.scale
.ordinal()
.rangeRoundBands([0, width], 0.1, 1);
scope.attrs.y = d3.scale
.linear()
.range([height, 0]);
scope.attrs.xAxis = d3.svg
.axis()
.scale(scope.attrs.x)
.orient('bottom');
scope.attrs.yAxis = d3.svg
.axis()
.scale(scope.attrs.y)
.orient('left')
.tickFormat(formatPercent);
};
},
post: function (scope, jqElm, attr) {
scope.$on('$destroy', function () { });
scope.$watch(
function () {
return scope.attrs.data;
},
function (nValue, oValue) {
if (!nValue) {
return;
}
if (nValue.length === 0) {
return;
}
var data = nValue;
scope.attrs.svg = d3.select(jqElm[0])
.data(data)
.enter()
.append('svg')
.attr('width', scope.attrs.width + scope.attrs.margin.left + scope.attrs.margin.right)
.attr('height', scope.attrs.height + scope.attrs.margin.top + scope.attrs.margin.bottom)
.append('g')
.attr('transform', 'translate(' + scope.attrs.margin.left + ',' + scope.attrs.margin.top + ')');
data.forEach(function (d) {
d.frequency = +d.frequency;
});
scope.attrs.x.domain(data.map(function (d) {
return d.letter;
}));
scope.attrs.y.domain([0, d3.max(data, function (d) {
return d.frequency;
})]);
scope.attrs.svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + scope.attrs.height + ')')
.call(scope.attrs.xAxis);
scope.attrs.svg.append('g')
.attr('class', 'y axis')
.call(scope.attrs.yAxis)
.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 6)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Frequency');
scope.attrs.svg.selectAll('.bar')
.data(data)
.enter().append('rect')
.attr('class', 'bar')
.attr('x', function (d) {
return scope.attrs.x(d.letter);
})
.attr('width', scope.attrs.x.rangeBand())
.attr('y', function (d) {
return scope.attrs.y(d.frequency);
})
.attr('height', function (d) {
return scope.attrs.height - scope.attrs.y(d.frequency);
});
}
);
}
};
}
function ctrl($scope, $element, $attrs) {
var vm = $scope;
if (!isDef(vm.attrs) || vm.attrs === null) {
vm.attrs = ConstructorD3Bar.create({ });
}
var attrs = vm.attrs;
}
}
})(window.angular, window.d3);
<div id="{{ attrs.id }}" class="D3Bar" ng-class="attrs.theme" ng-init="initWidget()">
</div>
Remove .data().enter in .select
scope.attrs.svg = d3.select(jqElm[0])
.append('svg')
.attr('width', scope.attrs.width + scope.attrs.margin.left + scope.attrs.margin.right)
.attr('height', scope.attrs.height + scope.attrs.margin.top + scope.attrs.margin.bottom)
.append('g')
.attr('transform', 'translate(' + scope.attrs.margin.left + ',' + scope.attrs.margin.top + ')');

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