Delete tool/icon in jointjs - backbone.js

I have create a circle shape as a delete tool to delete shapes. I got the information from this link: JointJS Element with ports and tool items (delete, settings etc.)
Almost implemented it correctly but some how the delete shape(circle) doesn't have 'X' mark on it and also delete event is not fired. If any body worked on it already, please guide me here. Thanks
Code:
var clientX, clientY, offsetX, offsetY;
var x, y;
var shapeId = "";
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({
el: $('#canvas'),
id: 'myPaper',
model: graph,
gridSize: 1,
defaultLink: new joint.shapes.devs.Link({
router: {name: 'orthogonal', args: {maximumLoops: 1000, excludeTypes: ['container']}},
connector: {name: 'rounded'},
attrs: {'.marker-target': {d: 'M 10 0 L 0 5 L 10 10 z'}},
labels: [{position: .5, attrs: {text: {text: 'label', 'font-size': '13', 'stroke': 'black', 'stroke-width': '0.1'}}}]
}),
validateConnection: function (cellViewS, magnetS, cellViewT, magnetT, end, linkView) {
if (magnetS && magnetS.getAttribute('type') === 'input')
return true;
if (cellViewS === cellViewT)
return false;
return (magnetS !== magnetT);
return magnetT && magnetT.getAttribute('type') === 'input';
},
markAvailable: true
});
joint.shapes.devs.TooledModel = joint.shapes.devs.Model.extend(_.extend({}, joint.plugins.TooledModelInterface, {
// markup: '<g class="rotatable"><g class="scalable"><rect class="body"/></g><text class="t"/><g class="inPorts"/><g class="outPorts"/><g class="moveTool"/><g class="resizeTool"/><g class="portsTool"/></g>',
markup: ['<g class="rotatable">',
'<g class="scalable">',
'<rect class="body"/>',
'<g xmlns="http://www.w3.org/2000/svg" transform="translate(-549.49953,-824.87393)" id="layer1">',
'<g transform="matrix(0.933025,0,0,-0.2986125,549.49953,846.37362)" id="g3553">',
'<g transform="scale(0.98976,3.0047)" id="g3555">',
'<g clip-path="url(#clipPath3559)" id="g3557">',
'<path d="M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z" id="path3563" style="fill:#b8cde8;fill-opacity:1;fill-rule:evenodd;stroke:none"/>',
'</g>',
'</g>',
'</g>',
'</g>',
'</g>',
'<text class="t"/>',
'<g class="inPorts"/>',
'<g class="outPorts"/>',
'<g class="moveTool"/>',
'<g class="resizeTool"/>',
'<g class="portsTool"/>',
'<g class="deleteTool"/>',
'<circle class="deleteTool" id="deleteTool" fill="red" r="8"/>',
'<title class="tooltip"/>',
'</g>'].join(''),
defaults: joint.util.deepSupplement({
type: 'devs.TooledModel',
position: {x: 200, y: 100},
size: {width: 71, height: 625},
attrs: {
// '.label': {text: ""},
'text': {'font-size': 14, text: '', 'ref-x': .5, 'ref-y': .5, ref: '.body', 'y-alignment': 'middle', 'x-alignment': 'middle', fill: 'black', 'font-weight': 'normal', 'font-family': 'Arial, helvetica, sans-serif'},
rect: {stroke: '#008B8B', fill: '#EEEEEE', 'stroke-width': 2}, '.': {magnet: false},
'.inPorts circle': {type: 'input'},
'.outPorts circle': {type: 'output'},
'.port-body': {r: 3},
'.body': {
width: 151, height: 151,
stroke: 'none'
},
}
}, joint.shapes.devs.Model.prototype.defaults)
}
));
joint.shapes.devs.TooledModelView = joint.shapes.devs.ModelView.extend(joint.plugins.TooledViewInterface);
function getId(id)
{
shapeId = id;
console.log(shapeId);
}
function createShape(event)
{
var $stageContainer = $("#canvas");
var stageOffset = $stageContainer.offset();
clientX = event.clientX;
clientY = event.clientY;
offsetX = stageOffset.left;
offsetY = stageOffset.top;
x = clientX - offsetX;
y = clientY - offsetY;
switch (shapeId)
{
case('newTask'):
createRect(x, y);
break;
default:
console.log("Nothing to drag");
}
}
function createRect(x, y)
{
var rect = new joint.shapes.devs.TooledModel({
position: {x: x, y: y},
size: {width: 120, height: 85},
inPorts: [''],
outPorts: [''],
attrs: {
text: {text: 'Edit me', fill: 'black'},
rect: {
fill: '#D6F2FC', rx: 7, ry: 15, opacity: .80, 'stroke-width': 2
},
'.inPorts circle': {type: 'input'},
'.outPorts circle': {type: 'output'},
'.port-body': {r: 3}
}
});
graph.addCell(rect);
}
// First, unembed the cell that has just been grabbed by the user.
paper.on('cell:pointerdown', function (cellView) {
var cell = cellView.model;
if (!cell.get('embeds') || cell.get('embeds').length === 0) {
// Show the dragged element above all the other cells (except when the
// element is a parent).
cell.toFront();
_.invoke(graph.getConnectedLinks(cell), 'toFront');
}
if (cell.get('parent')) {
graph.getCell(cell.get('parent')).unembed(cell);
}
});
// When the dragged cell is dropped over another cell, let it become a child of the element below.
paper.on('cell:pointerup', function (cellView) {
if (cellView.model.isLink())
return;
var cell = cellView.model;
var cellViewsBelow = paper.findViewsFromPoint(cell.getBBox().center());
if (cellViewsBelow.length) {
// Note that the findViewsFromPoint() returns the view for the `cell` itself.
var cellViewBelow = _.find(cellViewsBelow, function (c) {
return c.model.id !== cell.id;
});
// Prevent recursive embedding.
if (cellViewBelow && cellViewBelow.model.get('parent') !== cell.id) {
cellViewBelow.model.embed(cell);
}
}
});
Tooled model interface contains:
deleteToolMarkup: '<circle fill="red" r="11"/><path transform="scale(.8) translate(-16, -16)" d="M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z"/><title>Remove this element from the model</title>',
joint.plugins.TooledViewInterface contains:
//delete tool
renderDeleteTool: function () {
var deleteContainer = this.$('.deleteTool').empty();
var markup = V(this.model.deleteToolMarkup);
for (var id in markup)
deleteContainer.append(markup[id].node);
},

Related

How to add labels to the bubbles in Bubble Graph of react-chartjs-2 package? [duplicate]

I'm creating a bubble chart using chartjs. I am able to create tooltips that describe each of the bubbles, but users of my chart may not be able to hover over it to see the tooltip. The BubbleData object format doesn't include a label element (I put one in anyway - no luck), I've tried the "labels" element for the Chart Data object (even though the docs say this is for Category labels - you never know!), and everything I can think of to put label on the bubble.
Is there a tooltip configuration that makes all the tooltips visible at all times? This would work for me as well.
Thanks;
Glenn
I was looking for the same thing and figured out how to do it.
add in the datasets the title:"dataTitle3" you want to show.
use the data labeling plugin.
simple code manipulation achieves what you want using
dataset.title
I have made a sample but I think you could find out how and represent the data you want if you play with: external link
new Chart(document.getElementById("bubble-chart"), {
type: 'bubble',
data: {
labels: "Africa",
datasets: [{
label: ["China"],
backgroundColor: "rgba(255,221,50,0.2)",
borderColor: "rgba(255,221,50,1)",
title: "dataTitle1", //adding the title you want to show
data: [{
x: 21269017,
y: 5.245,
r: 15
}]
}, {
label: ["Denmark"],
backgroundColor: "rgba(60,186,159,0.2)",
borderColor: "rgba(60,186,159,1)",
title: "dataTitle2",
data: [{
x: 258702,
y: 7.526,
r: 10
}]
}, {
label: ["Germany"],
backgroundColor: "rgba(0,0,0,0.2)",
borderColor: "#000",
title: "dataTitle3", //adding the title you want to show
data: [{
x: 3979083,
y: 6.994,
r: 15
}]
}, {
label: ["Japan"],
backgroundColor: "rgba(193,46,12,0.2)",
borderColor: "rgba(193,46,12,1)",
title: "dataTitle4", //adding the title you want to show
data: [{
x: 4931877,
y: 5.921,
r: 15
}]
}]
},
options: {
title: {
display: true,
text: 'Predicted world population (millions) in 2050'
},
scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: "Happiness"
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: "GDP (PPP)"
}
}]
}
}
});
Chart.plugins.register({
afterDatasetsDraw: function(chart, easing) {
var ctx = chart.ctx;
chart.data.datasets.forEach(function(dataset, i) {
var meta = chart.getDatasetMeta(i);
if (meta.type == "bubble") { //exclude scatter
meta.data.forEach(function(element, index) {
// Draw the text in black, with the specified font
ctx.fillStyle = 'rgb(0, 0, 0)';
var fontSize = 13;
var fontStyle = 'normal';
var fontFamily = 'Helvetica Neue';
ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
// Just naively convert to string for now
var dataString = dataset.data[index].toString();
// Make sure alignment settings are correct
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
var padding = 15;
var position = element.tooltipPosition();
ctx.fillText(dataset.title, position.x, position.y - (fontSize / 2) - padding);
});
} //if
});
}
});
<canvas id="bubble-chart" width="800" height="800"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js" integrity="sha512-ElRFoEQdI5Ht6kZvyzXhYG9NqjtkmlkfYk0wr6wHxU9JEHakS7UJZNeml5ALk+8IKlU6jDgMabC3vkumRokgJA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
ChartJs has a plugin now for this.
https://github.com/chartjs/chartjs-plugin-datalabels
Just install it using nuget or bower and add the reference of it. It wil automatically set z as label
The sytax has changed with chart.js V3 in a few places so I thought I'd share my variation on the chosen answer.
Chart.register({
id: 'permanentLabel',
afterDatasetsDraw: function (chart, args, options) {
var ctx = chart.ctx
chart.data.datasets.forEach(function (dataset, i) {
var meta = chart.getDatasetMeta(i)
if (meta.type == 'bubble') {
meta.data.forEach(function (element, index) {
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
var position = element.tooltipPosition()
ctx.fillText(dataset.data[index].label.toString(), position.x, position.y - dataset.data[index].r - Chart.defaults.font.size)
})
}
})
},
})
I have an some extra code, to avoid overlapping of labels.
var labelPlugin = {
myTimeout: null,
getNewYPostion:function(item, alreadyUsed, fontSize){
for(let i of alreadyUsed){
if((item.y_from >= i.y_from && item.y_from <= i.y_to) || (item.y_to>= i.y_from && item.y_to <= i.y_to)){
if((item.x_from >= i.x_from && item.x_from <= i.x_to) || (item.x_to>= i.x_from && item.x_to <= i.x_to)){
item.y_from=i.y_to+(fontSize*0.1);
item.y_to=item.y_from+fontSize;
return this.getNewYPostion(item, alreadyUsed, fontSize);
}
}
}
return item;
},
afterDatasetsDraw: function (chart, args, options) {
var ctx = chart.ctx;
var that=this;
clearTimeout(this.myTimeout);
this.myTimeout = setTimeout(function () {
var alreadyUsed = [];
chart.data.datasets.forEach(function (dataset, i) {
var txt = dataset.label;
var txtSize = ctx.measureText(txt).width;
var meta = chart.getDatasetMeta(i);
if (meta.type === "bubble") { //exclude scatter
var fontSize = 10;
var fontStyle = 'normal';
var fontFamily = 'Helvetica Neue';
ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
ctx.fillStyle = 'rgb(0, 0, 0)';
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
var padding, position, x_from, x_to, y, y_from, y_to;
meta.data.forEach(function (element, index) {
padding = element.options.radius;
position = element.tooltipPosition();
x_from = position.x + padding + 5; // left
x_to = x_from + txtSize; // left
y = position.y; // top
y_from = y - (fontSize * 0.5);
y_to = y + (fontSize * 0.5);
var item={
'y_from': y_from,
'y_to': y_to,
'x_from': x_from,
'x_to': x_to,
};
item=that.getNewYPostion(item, alreadyUsed, fontSize);
alreadyUsed.push(item);
ctx.fillText(txt, item.x_from, item.y_from+(0.5*fontSize));
});
}
});
}, 500);
}
};
In 2022 the current version is 3.9.1 here is a working snippet:
const $canvas = document.getElementById('chart')
const popData = {
datasets: [{
label: ['Deer Population'],
data: [{
x: 100,
y: 0,
r: 25,
label: 'Russia',
}, {
x: 60,
y: 30,
r: 20,
label: 'China',
}, {
x: 40,
y: 60,
r: 25,
label: 'Canada',
}, {
x: 80,
y: 80,
r: 40,
label: 'US',
}, {
x: 20,
y: 30,
r: 25,
label: 'Africa',
}, {
x: 0,
y: 100,
r: 5,
label: 'Europe',
}],
backgroundColor: "#FF9966"
}]
};
const bubbleChart = new Chart($canvas, {
type: 'bubble',
data: popData
});
const fontSize = Chart.defaults.font.size
Chart.register({
id: 'permanentLabel',
afterDatasetsDraw: (chart, args, options) => {
const ctx = chart.ctx
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
chart.data.datasets.forEach((dataset, i) => {
const meta = chart.getDatasetMeta(i)
if (meta.type !== 'bubble') return
meta.data.forEach((element, index) => {
const item = dataset.data[index]
const position = element.tooltipPosition()
ctx.fillText(item.label.toString(), position.x, position.y - item.r - fontSize)
})
})
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<canvas id="chart" width="600" height="180"></canvas>

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.

nvd3.js pie chart export to Excel in angular js

I am using nvd3.js to create a pie chart.
I would like to export this chart to Excel.
For export I am using FileSaver.js
My HTML looks like:
<body ng-controller="MainCtrl">
<button ng-click="exportData()">click</button>
<div id="charts">
<nvd3 options="options" data="data"></nvd3>
</div>
</body>
My code looks like:
var app = angular.module('plunker', ['nvd3']);
app.controller('MainCtrl', function($scope) {
$scope.exportData = function () {
alert("function call");
var blob = new Blob([document.getElementById('charts').innerHTML ], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"
});
saveAs(blob, "Report.xls");
};
$scope.options = {
chart: {
type: 'pieChart',
height: 500,
x: function(d){return d.key;},
y: function(d){return d.y;},
showLabels: true,
transitionDuration: 500,
labelThreshold: 0.01,
legend: {
margin: {
top: 10,
right: 35,
bottom: 5,
left: 0
}
},
}
};
$scope.data = [
{
key: "suraj",
y: 5
},
{
key: "darshan",
y: 2
},
{
key: "kapil",
y: 9
},
{
key: "Four",
y: 7
},
{
key: "Five",
y: 4
},
{
key: "Six",
y: 3
},
{
key: "Seven",
y: .5
}
];
});
Thanks for your help!

AngularJS : link between directive and controller

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();
});

Resources