AngularJS : link between directive and controller - angularjs

I'm trying to call a function of my directive in my controller. I would like to reshape a curve. At the moment, I can do within the Directive. But I need to outsource the call. Do you know how can I proceed?
My directive :
.directive('drawCharts', function () {
return function (scope, element, attrs) {
scope.$watch('curveArray', function () {
drawPlot();
}, true);
var drawPlot = function () {
/* Define var for interactive chart */
var tickInterval = scope.intervalMillisecond;
var typeLine = 'line';
var chart = function (curveArrayShow, typeLine, optionLineBool, yAxisCurveArrayShow, pointStart, pointEnd) {
var optionLine = { dataLabels: { enabled: optionLineBool, y: -20 }};
new Highcharts.Chart({
chart: {
pinchType: 'x',
renderTo: 'container',
type: typeLine,
backgroundColor:'rgba(255, 255, 255, 0.95)',
events: {
load: function(event) {
//alert ('Chart loaded : ' + event);
//scope.isLoading = false;
}
}
},
legend: {
enabled: false
},
title: {
text: ''
},
xAxis: [{
type: 'datetime',
labels: {
format: '{value: <b>%d/%m</b> %H:%M}',
staggerLines: 1
},
opposite: true,
plotLines: [{
color: '#FF0000', // Red
width: 2,
value: new Date().getTime() // Position, you'll have to translate this to the values on your x axis
}],
min: pointStart,
max: pointEnd,
minPadding: 0,
maxPadding: 0,
startOnTick: false, // allow to start not from tick
endOnTick: false,
tickInterval: tickInterval
}],
yAxis: yAxisCurveArrayShow,
tooltip: {
style:{ zindex: 10 },
xDateFormat: '%d/%m %H:%M',
shared: true,
},
plotOptions: {
column: { borderWidth: 1, borderColor: '#000000' },
spline: {
marker: {
radius: 4,
lineColor: '#666666',
lineWidth: 1
}
},
series: {
dataLabels: {
enabled: optionLineBool,
style: {font: 'bold 11px Arial', textShadow: '0 0 3px white, 0 0 3px white'}
},
marker: {
lineColor: null,
radius: 6,
states: {
hover: {
radius: 10
}
}
}
},
line: optionLine
},
series: curveArrayShow
}}
var pointStart = scope.intervalResearchTime.startDateTime + scope.intervalMillisecond; //remove padding that adding for serie type column
var pointEnd = scope.intervalResearchTime.endDateTime - scope.intervalMillisecond; //remove padding that adding for serie type column
chart(scope.curveArray, typeLine, false, scope.yAxisCurveArray, pointStart, pointEnd);
}
};
In my controller i need to update my chart. So i would like to call the function :
$scope.redrawCurve = function(_index) {
/* My algorithm ...... */
chart(curveArrayShow, typeLine, false, $scope.yAxisCurveArray, pointStart, pointEnd);
};
Thx,
Alex

My suggestion is to use event to notify the directive to redraw the plot, like this:
Controller:
$scope.redrawCurve = function(_index) {
/* My algorithm ...... */
$scope.$broadcast('redraw', arg1, arg2, /* other necessary arguments */);
};
Directive:
scope.$on('redraw', function(arg1, arg2, /* other necessary arguments */) {
drawPlot();
});

Related

Integrating Highcharts Sparkline with Angular JS UI Grid

I am trying to integrate highcharts sparkline with angular ui-grid directive but unable to plot the sparkline. When we try to dynamically plot the sparklines using ui-grid nothing gets plotted. I have made necessary changes to the sparkline code as well yet unable to find what is the issue. We need age column to have highcharts sparkline. Any pointer will be of great help.
$scope.gridOptions = {
enableFiltering: false,
enableSorting: true,
}
$scope.gridOptions.columnDefs = [{
name: 'id'
}, {
name: 'name'
}, {
name: 'age',
cellTemplate: '<div id="table-sparkline" data-sparkline="71, 78, 39, 66"></div>'
}, {
name: 'address.city'
}];
$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/500_complex.json')
.success(function(data) {
$scope.gridOptions.data = data;
console.log(JSON.stringify(data));
/**
* Create a constructor for sparklines that takes some sensible defaults and merges in the individual
* chart options. This function is also available from the jQuery plugin as $(element).highcharts('SparkLine').
*/
Highcharts.SparkLine = function(a, b, c) {
var hasRenderToArg = typeof a === 'string' || a.nodeName,
options = arguments[hasRenderToArg ? 1 : 0],
defaultOptions = {
chart: {
renderTo: (options.chart && options.chart.renderTo) || this,
backgroundColor: null,
borderWidth: 0,
type: 'area',
margin: [2, 0, 2, 0],
width: 120,
height: 20,
style: {
overflow: 'visible'
},
// small optimalization, saves 1-2 ms each sparkline
skipClone: true
},
title: {
text: ''
},
credits: {
enabled: false
},
xAxis: {
labels: {
enabled: false
},
title: {
text: null
},
startOnTick: false,
endOnTick: false,
tickPositions: []
},
yAxis: {
endOnTick: false,
startOnTick: false,
labels: {
enabled: false
},
title: {
text: null
},
tickPositions: [0]
},
legend: {
enabled: false
},
tooltip: {
backgroundColor: null,
borderWidth: 0,
shadow: false,
useHTML: true,
hideDelay: 0,
shared: true,
padding: 0,
positioner: function(w, h, point) {
return {
x: point.plotX - w / 2,
y: point.plotY - h
};
}
},
plotOptions: {
series: {
animation: false,
lineWidth: 1,
shadow: false,
states: {
hover: {
lineWidth: 1
}
},
marker: {
radius: 1,
states: {
hover: {
radius: 2
}
}
},
fillOpacity: 0.25
},
column: {
negativeColor: '#910000',
borderColor: 'silver'
}
}
};
options = Highcharts.merge(defaultOptions, options);
return hasRenderToArg ?
new Highcharts.Chart(a, options, c) :
new Highcharts.Chart(options, b);
};
var start = +new Date(),
$tds = $('div[data-sparkline]'),
fullLen = $tds.length,
n = 0;
// Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
// can take some seconds, so we split the input into chunks and apply them in timeouts
// in order avoid locking up the browser process and allow interaction.
function doChunk() {
var time = +new Date(),
i,
len = $tds.length,
$td,
stringdata,
arr,
data,
chart;
for (i = 0; i < len; i += 1) {
$td = $($tds[i]);
stringdata = $td.data('sparkline');
arr = stringdata.split('; ');
data = $.map(arr[0].split(', '), parseFloat);
chart = {};
if (arr[1]) {
chart.type = arr[1];
}
$td.highcharts('SparkLine', {
series: [{
data: data,
pointStart: 1
}],
tooltip: {
headerFormat: '<span style="font-size: 10px">' + $td.parent().find('div').html() + ', Q{point.x}:</span><br/>',
pointFormat: '<b>{point.y}.000</b> USD'
},
chart: chart
});
n += 1;
// If the process takes too much time, run a timeout to allow interaction with the browser
if (new Date() - time > 500) {
$tds.splice(0, i + 1);
setTimeout(doChunk, 0);
break;
}
}
}
doChunk();
Plunker

Set background color of Angular-nvD3

I am using Angular-nvD3 in my Charts and I would like to change the background of this chart like the picture example. Can anyone help me please?
Here its the HTML code:
<div class="col-md-6">
<nvd3 options="optionsrigidez" data="datarigidez" class="with-3d-shadow with-transitions"></nvd3>
</div>
And here its the angular params:
1. Options:
$scope.optionsrigidez = {
chart: {
type: 'lineChart',
height: 250,
reduceXTicks: true, // if false a tick will show for every data point
margin: {
top: 20,
right: 20,
bottom: 40,
left: 55
},
x: function (d) { return d.x; },
y: function (d) { return d.y; },
useInteractiveGuideline: true,
dispatch: {
stateChange: function (e) { console.log("stateChange"); },
changeState: function (e) { console.log("changeState"); },
tooltipShow: function (e) { console.log("tooltipShow"); },
tooltipHide: function (e) { console.log("tooltipHide"); }
},
yDomain: [0.0, 100.0],
showLegend: false,
xAxis: {
axisLabel: 'Data da análise',
tickFormat: function (d) {
return daysOfReport[d];
},
rotateLabels: -1
},
yAxis: {
axisLabel: 'kV',
tickFormat: function (d) {
return d3.format('.01f')(d);
},
axisLabelDistance: -10
},
callback: function (chart) {
//console.log("!!! lineChart callback !!!");
}
},
title: {
enable: true,
text: 'Rigidez Dielétrica - Calota'
},
caption: {
enable: true,
html: '<b>Gráfico 3.</b> É uma medida da capacidade do óleo resistir à solicitação elétrica. Revela também a presença de impurezas polares como a água e outros oxigenados e sólidos (NBR 6869). Fonte: <a href="http://www.filtroil.ind.br/analise-de-oleo-isolante">Filtroil.<a/>',
css: {
'text-align': 'justify',
'margin': '10px 13px 0px 7px'
}
}
};
Data:
function rigidez_function() {
var rigidez = [];
for (var i = 0; i < $scope.RelatorioOleo_analisesFQ.length; i++) {
rigidez.push({ x: i, y: $scope.RelatorioOleo_analisesFQ[i].calota });
}
//Line chart data should be sent as an array of series objects.
return [
{
values: rigidez, //values - represents the array of {x,y} data points
key: 'Rigidez Dielétrica', //key - the name of the series.
color: '#5A5A5A', //color - optional: choose your own line color.
strokeWidth: 2,
//classed: 'dashed'
}
];
};
$scope.datarigidez = rigidez_function();
Probably a bit late, but yes you can!
You have to create a MultiChart and draw the colored zones as 'stacked areas'. I've created a plunk here: http://plnkr.co/hW3Anw
chart: {
type: 'multiChart',
height: 450,
margin : {
top: 30,
...
testdata[1].type = "area"
testdata[1].yAxis = 1
testdata[1].values = [{x: 0, y: -0.5}, {x: 55, y: -0.5}]
testdata[2].type = "area"
testdata[2].yAxis = 1
testdata[2].values = [{x: 0, y: -5}, {x: 55, y: -5}]
...

Jointjs and angular : ng click doesn't work

I am creating an element with joint js and putting it inside a paper. The element has an ng-click directive in a pencil. However when I click on the element
The element
joint.shapes.flowie.Rect = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
markup: '<g class="rotatable" ><g class="scalable"><rect class="body"/></g><text class="label"/><text region="" transform="translate(40,10)" ng-init="alert()" ng-click="loadStep(workflow.steps[this.stepName])" class="fa edit fa-pencil"></text><g class="inPorts"/><g class="outPorts"/></g>',
portMarkup: '<g class="port port<%= id %>"><circle class="port-body"/><text class="port-label"/></g>',
defaults: joint.util.deepSupplement({
type: 'devs.Model',
size: { width: 1, height: 1 },
inPorts: [],
outPorts: [],
attrs: {
'.': { magnet: false },
'.body': {
width: 150, height: 350,
stroke: '#000000'
},
'.port-body': {
r: 8,
magnet: true,
stroke: '#000000'
},
text: {
// 'pointer-events': 'none'
},
'.label': { text: 'Model', 'ref-x': .5, 'ref-y': 10, ref: '.body', 'text-anchor': 'middle', fill: '#000000' },
'.inPorts .port-label': { x:-15, dy: 4, 'text-anchor': 'end', fill: '#000000'},
".inPorts circle": {type:"input", magnet:"passive" },
'.outPorts .port-label':{ x: 15, dy: 4, fill: '#000000',type:"output" }
}
}, joint.shapes.basic.Generic.prototype.defaults),
getPortAttrs: function(portName, index, total, selector, type) {
var attrs = {};
var portClass = 'port' + index;
var portSelector = selector + '>.' + portClass;
var portLabelSelector = portSelector + '>.port-label';
var portBodySelector = portSelector + '>.port-body';
attrs[portLabelSelector] = { text: portName };
attrs[portBodySelector] = { port: { id: portName || _.uniqueId(type) , type: type } };
attrs[portSelector] = { ref: '.body', 'ref-y': (index + 0.5) * (1 / total) };
if (selector === '.outPorts') { attrs[portSelector]['ref-dx'] = 0; }
return attrs;
}
}));
There is a saveStep function triggered by saving a form. The form contains some metadata for each element
I then do the following to add the step to the graph
shape = new joint.shapes.flowie.Start({
position: { x: 10, y: 10 },
size: { width: 100, height: 30 },
attrs: { rect: { fill: 'blue' }, '.label': { text: step.stepName, fill: 'white' } },
stepName:name
});
shape.set('inPorts', []);
shape.set('outPorts', ['OUT']);
graph.addCells([shape])
I have heard of the compile directive but can't figure out a way to use it.

Highcharts-ng, excessive re rendering

I wonder how I should go about having better animations when adding points to a area plot. In regular highcharts this is done pretty smooth but using highcharts-ng it rerenders a huge chunk of the chart.
I have two fiddels that shows the issue. Maby there is a simple way to solve this ?
Highcharts-ng
http://jsfiddle.net/Cp73s/3399/
var myapp = angular.module('myapp', ["highcharts-ng"]);
myapp.controller('myctrl', function ($scope) {
$scope.addPoints = function () {
var seriesArray = $scope.highchartsNG.series
var rndIdx = Math.floor(Math.random() *10+7);
$scope.highchartsNG.series[0].data.push(rndIdx);
};
$scope.highchartsNG = {
options: {
chart: {
type: 'area'
},
plotOptions: {
area: {
fillOpacity: 0.15,
dataLabels: {
allowOverlap: true,
enabled: true,
padding: 0,
style: {
fontSize: '25px'
}
},
enableMouseTracking: true
}
},
},
series: [{
data: [10, 15, 12, 8, 7]
}]
}
});
Regular-highcharts
http://jsfiddle.net/m8Lavyrc/3/
$(function () {
$('#container').highcharts({
chart: {
type: 'area'
},
plotOptions: {
area: {
fillOpacity: 0.15,
dataLabels: {
allowOverlap: true,
enabled: true,
padding: 0,
style: {
fontSize: '25px'
}
},
enableMouseTracking: true
}
},
series: [{
data: [10, 15, 12, 8, 7]
}]
});
// the button action
var i = 0;
$('#button').click(function () {
var chart = $('#container').highcharts();
chart.series[0].addPoint(Math.floor(Math.random() *10+7));
});
});
Tnx

Render Two charts separate charts using angular js directives

I am trying to render two seperate charts using seperate directives for each charts, since the data is different ( also I am no expert in AngualrJs ). But only one chart was rendering to view. Please can someone help with what I have to do so that I can see both charts.Thanks.
'use strict';
angular.module('AngularApp',['AngularApp.directives']);
/*Controllers*/
var HighChartController = function HighChartController($scope) {
$scope.templateUrl = '/_layouts/AngularControls/TestController/View2.html';
$scope.type = '107';
$scope.initData = function () {
$scope.data = [
['Fire', 47.0],
['Wind', 33.0],
['Natural', 20.0]
];
}
$scope.loadChart = function () {
$scope.data1 = [60];
$scope.data2 = [40];
}
$scope.initData();
$scope.loadChart();
}
/* Directives */
angular.module('AngularApp.directives', []).
directive('drawPieChart', function () {
return function (scope, element, attrs) {
var container = $(element).attr("id");
scope.$watch('data', function () {
console.log('data');
drawPlot();
}, true);
var drawPlot = function () {
var chart;
chart = new Highcharts.Chart({
chart: {
renderTo: container,
margin: [0, 0, 0, 0],
spacingTop: 0,
spacingBottom: 0,
spacingLeft: 0,
spacingRight: 0
},
title: {
text: null
},
credits: {
enabled: false
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage}%</b>',
percentageDecimals: 1
},
plotOptions: {
pie: {
size: '100%',
dataLabels: {
enabled: false
}
}
},
series: [{
type: 'pie',
name: 'Browser share',
data: scope.data
}]
});
}
}
});
angular.module('AngularApp.directives', []).
directive('drawBarChart', function () {
return function (scope, element, attrs) {
var container = $(element).attr("id");
scope.$watch('data', function () {
drawPlot();
}, true);
var drawPlot = function () {
var chart = new Highcharts.Chart({
chart: {
type: 'column',
renderTo: container,
marginRight: 50,
events: {
}
},
title: {
text: 'Test Scores',
style: {
color: 'black',
fontWeight: '700',
fontFamily: 'Arial',
fontSize: 20
}
},
xAxis: {
categories: [],
title: {
text: null
},
gridLineWidth: 0,
minorGridLineWidth: 0,
labels: {
style: {
color: 'black',
fontWeight: '700',
fontFamily: 'Arial',
fontSize: 11,
width: 90
}
}
},
yAxis: {
min: 0,
max: 100,
gridLineWidth: 0,
minorGridLineWidth: 0,
labels: {
enabled: false
},
title: {
text: null
}
},
tooltip: {
valueSuffix: ' million'
},
plotOptions: {
series: {
stacking: 'percent'
},
bar: {
dataLabels: {
enabled: false
}
}
},
legend: {
enabled: false,
layout: 'vertical',
align: 'right',
verticalAlign: 'bottom',
x: -40,
y: 100,
floating: true,
borderWidth: 1,
backgroundColor: '#FFFFFF',
shadow: true
},
credits: {
enabled: false
},
series: [{
name: 'null',
data: scope.data2,
borderRadius: 0,
color: "gray"
}, {
name: 'Values',
data: scope.data1,
color: "green",
borderRadius: 0
}]
});
}
}
});
Here is the markup
<div id="barChartContainer" draw-bar-chart =""></div>
</div>
<div id="pieChartContainer" draw-pie-chart="">
</div>
As Oledje mentioned, you declared the AngularApp.directives twice, but there was also an issue with how you are actually referencing the data for the charts in the directive code. I would recommended that you create an isolated scope for each directive and map the properties for the chart data in the scope definition.
So instead of
.directive('drawPieChart', function () {
return function (scope, element, attrs) {
var container = $(element).attr("id");
scope.$watch('data', function () {
console.log('data');
drawPlot();
}, true);
var drawPlot = function () {...};
};
}
You should do
.directive('drawPieChart', function () {
return {
restrict: 'E',
scope: {
chartData: "="
},
link: function (scope, element, attrs) {
scope.$watch('chartData', function (newVal,oldVal) {
if (newVal) {
drawPlot();
}
}, true);
var drawPlot = function () {
// use scope.chartData for the data
};
}
};
}
And then you also need the corresponding HTML
<draw-pie-chart chart-data="pieChartData">
And in your Controller do $scope.pieChartData=[];
Here is a jsFiddle with all of my changes: http://jsfiddle.net/callado4/9far5/5/ (look at the history to see how I progressed)
I think that your problem is that you declare a module twice.
try write not
angular.module('AngularApp.directives', []).
directive('drawPieChart'...)
angular.module('AngularApp.directives', []).
directive('drawBarChart'...)
but
angular.module('AngularApp.directives', []).
directive('drawPieChart'...).
directive('drawBarChart'...)
or
var app = angular.module('AngularApp.directives', []);
app.controller('Ctrl', ...)
app.directive('drawPieChart'...);
app.directive('drawBarChart'...);
Examples:
http://jsfiddle.net/GDQ6B/2/
http://jsfiddle.net/EYz9U/1/

Resources