How to load a directive template before evaluating javascript - javascript

I'm using KineticJS in conjunction with AngularJS and I want to be able to stash the necessary javascript into a directive. All of the examples I've seen for KineticJS wrap the required logic in a script tag using the defer attribute, i.e.
<script defer="defer">
window.onload = function() { ... }
</script>
Is it possible to load the template of the directive while deferring the execution of any business logic (in an equivalent way)? I've tried using the controller, link, compile functions to no avail. Here's an example:
'use strict';
angular.module('app')
.directive('canvasInitializer', ['$window', function ($window) {
return {
template: "<div id='canvas-container'></div>", // load this!
restrict: 'C',
compile: function (element, attrs) {
return {
post: function(scope, element, attrs) {
// defer this?
$window.onload = function () {
var stage = new Kinetic.Stage({
container: 'canvas-container',
width: 800,
height: 600
});
var layer = new Kinetic.Layer();
var blueRect = new Kinetic.Rect({
x: 50,
y: 75,
width: 100,
height: 50,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 4
});
layer.add(blueRect);
stage.add(layer);
}
}
}
}
}
}]);

Aaaaaaand suddenly it looks like I found the answer to my problem. Wrapping the logic in $timeout(function () { ... }) did the trick. Notice that I didn't even provide a specific time for $timeout.
'use strict';
angular.module('app')
.directive('canvasInitializer', ['$timeout', function ($timeout) {
return {
template: "<div id='canvas-container'></div>"
restrict: 'C',
link: function (scope, element, attrs) {
$timeout(function () {
var stage = new Kinetic.Stage({
container: 'canvas-container',
width: 800,
height: 600
});
var layer = new Kinetic.Layer();
var blueRect = new Kinetic.Rect({
x: 50,
y: 75,
width: 100,
height: 50,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 4
});
layer.add(blueRect);
stage.add(layer);
});
}
}
}]);

Related

How to pass the fetched node data from directive to controller

topology.controller.js
define(['app/topology/topology.module','app/topology/topology.services', 'app/topology/topology.directives'], function(topology, service) {
topology.controller('TopologyCtrl', ['$scope', '$rootScope', '$location', 'NetworkTopologySvc' , function ($scope, $rootScope, $location, NetworkTopologySvc) {
$rootScope['section_logo'] = 'assets/images/logo_topology.gif';
var graphRenderer = null;
$scope.createTopology = function() {
NetworkTopologySvc.getNode("flow:1", function(data) {
$scope.topologyData = data;
});
};
$scope.createTopology();
}]);
});
topology.directives.js
define(['app/topology/topology.module', 'vis'], function(topology, vis) {
topology.directive('topologySimple', function() {
// constants
var width = 800,
height = 800;
return {
restrict: 'E',
scope: {
topologyData: '='
},
link: function($scope, iElm, iAttrs, controller, $window, $location) {
$scope.$watch('topologyData', function (ntdata) {
if(ntdata){
// visinit(inNodes, inEdges, container, inOptions) {
var inNodes = $scope.topologyData.nodes;
var inEdges = $scope.topologyData.links;
var container = iElm[0];
// legend moved to topology controller
var data = {
nodes: inNodes,
edges: inEdges
};
var color = '#66FFFF',
hl = '#0066FF',
hover = '#33CC33',
BLACK = '#2B1B17';
var options =
{
width: '100%',
height: '750px',
nodes: {
widthMin: 20,
widthMax: 64,
fontColor: BLACK
},
edges: {
length: 80,
color: {
color: '#070707',
highlight: hl,
hover: hover
}
},
physics: {
barnesHut: {
gravitationalConstant: -7025
}
},
hover: true,
groups: {
'switch': {
shape: 'image',
image: 'assets/images/Device_switch_3062_unknown_64.png'
},
'host': {
shape: 'image',
image: 'assets/images/Device_pc_3045_default_64.png'
}
},
keyboard:true,
tooltip: {
delay: 300,
fontColor: "black",
fontSize: 14, // px
fontFace: "verdana",
color: {
border: "#666",
background: "#FFFFC6"
}
}
};
var graph = new vis.Graph(container, data, options);
return graph.on("click", function (params) {
console.log(params);
});
}
});
}
};
});
});
How to send the data received into 'params' to controller.
The params contains :
"nodes": [1,2],
"links": [3,4]
Please help me with this.
Any help would be appreciated.
You have several ways to do so.
using service or factory, but you can also pass data using $rootScope - not a good practice. simple $rootScope example:
in directive:
$rootScope.nodes = nodes;
and you can simple access them at your controller:

Joint JS - How apply an event on shapes.devs

I'm new with jointjs and I try to constraint a rectangle with ports to a line.
I tried to reproduce tutorial, that works with a basic.Circle, with a basic.Rect but not with devs.Model
Could someone explian me why and how to solve this problem?
Many thanks in advance!
Here is my code :
var width=400, height=1000;
var ConstraintElementView = joint.dia.ElementView.extend({
pointermove: function(evt, x, y) {
joint.dia.ElementView.prototype.pointermove.apply(this, [evt, 100, y]);
}
});
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({ el: $('#myholder'), width: width, height: height, gridSize: 1, model: graph, elementView: ConstraintElementView});
var m1 = new joint.shapes.devs.Model({
position: { x: 20, y: 20 },
size: { width: 90, height: 90 },
inPorts: [''],
outPorts: [''],
attrs: {
'.label': { text: 'Model', 'ref-x': .4, 'ref-y': .2 },
rect: { fill: '#2ECC71' },
'.inPorts circle': { fill: '#16A085' },
'.outPorts circle': { fill: '#E74C3C' }
}
});
var m2=m1.clone();
m2.translate(0,300);
var earth = new joint.shapes.basic.Circle({
position: { x: 100, y: 20 },
size: { width: 20, height: 20 },
attrs: { text: { text: 'earth' }, circle: { fill: '#2ECC71' } },
name: 'earth'
});
graph.addCell([m1, m2, earth]);
Why does it not work?
devs.Model is not rendered via ContraintElementView to the paper.
devs.Model uses devs.ModelView for rendering, basic.Circle and basic.Rect use ContraintElementView.
JointJS dia.Paper searches for a view defined in the same namespace as the model first. If found, it uses it. It uses one from the paper elementView option otherwise. i.e. joint.shapes.devs.ModelView found for devs.Model but no view found for basic.Circle (no joint.shapes.basic.RectView is defined)
How to make it work?
define elementView paper option as a function. In that case paper don't search the namespace and uses the result of the function first.
Note that in order to render ports devs.ModelView is still required.
i.e.
var paper = new joint.dia.Paper({
elementView: function(model) {
if (model instanceof joint.shapes.devs.Model) {
// extend the ModelView with the constraining method.
return joint.shapes.devs.ModelView.extend({
pointermove: function(evt, x, y) {
joint.dia.ElementView.prototype.pointermove.apply(this, [evt, 100, y]);
}
});
}
return ConstraintElementView;
}
});
http://jsfiddle.net/kumilingus/0bjqg4ow/
What is the recommended way to do that?
JointJS v0.9.7+
not to use custom views that restrict elements movement
use restrictTranslate paper option instead.
i.e.
var paper = new joint.dia.Paper({
restrictTranslate: function(elementView) {
// returns an area the elementView can move around.
return { x: 100, y: 0, width: 0, height: 1000 }
};
});
http://jsfiddle.net/kumilingus/atbcujxr/
I think this could help you :
http://jointjs.com/demos/devs

integrating angular and joint js

I am trying to integrate angular with joint js.I have wrapped the joint js content within angular directive but for some reasons, the code is not working.
view contains:
<joint-diagram graph="graph" width="width" height="height" grid-size="1" />
Directive:
app.directive('jointDiagram', [function () {
var directive = {
link: link,
restrict: 'E',
scope: {
height: '=',
width: '=',
gridSize: '=',
graph: '=',
}
};
return directive;
function link(scope, element, attrs) {
var diagram = newDiagram(scope.height, scope.width, scope.gridSize, scope.graph, element[0]);
}
function newDiagram(height, width, gridSize, graph, targetElement) {
var paper = new joint.dia.Paper({
el: targetElement,
width: width,
height: height,
gridSize: gridSize,
model: graph,
});
return paper;
}
}]);
graph,width and height are passed via a controller.Directive is only rendering the paper object without any nodes(cells)c passed via graph object.But when I print the paper object,it does contain graph object having nodes.what could be the reason behind this.
I'm not 100% certain of the underlying cause of this but since you're adding items to the graph before you create your Paper instance, they aren't drawn. You can use graph.resetCells() to trigger the redraw. For example, using the Hello World example provided in JointJS;
// Create an empty Graph instance and assign to the Paper instance
var graph = new joint.dia.Graph,
paper = new joint.dia.Paper({
el: element[0],
width: scope.width,
height: scope.height,
model: graph,
gridSize: scope.gridSize
}),
cells = [];
var rect = new joint.shapes.basic.Rect({
position: { x: 100, y: 30 },
size: { width: 100, height: 30 },
attrs: { rect: { fill: 'blue' }, text: { text: 'A Box', fill: 'white' } }
});
var rect2 = rect.clone();
rect2.translate(300);
var link = new joint.dia.Link({
source: { id: rect.id },
target: { id: rect2.id }
});
cells.push(rect, rect2, link);
// Now refresh the graph to ensure the nodes render
graph.resetCells(cells)

Angularjs - Calling a controller function inside directive

I'm trying to use jQuery Sparkline charts with Angularjs. I have multiple charts to display, so I've decided to create a function in the controller and call it for each chart(directive).
JS
controller
.controller('sparklineCtrl', [function(){
this.sparklineBar = function(id, values, height, barWidth, barColor, barSpacing) {
$('.'+id).sparkline(values, {
type: 'bar',
height: height,
barWidth: barWidth,
barColor: barColor,
barSpacing: barSpacing
})
}
}])
directive
.directive('sparklineBar', function(){
return {
restrict: 'A',
scope: {
slBar: '&'
},
link: function(scope, element) {
scope.slBar('stats-bar', [6,4,8,6,5,6,7,8,3,5,9,5,8,4,3,6,8], '45px', 3, '#fff', 2);
}
}
})
HTML
<div data-ng-controller="sparklineCtrl as spctrl">
<div class="chart" id="stats-bar" data-sparkline-bar data-sl-bar="spctrl.sparklineBar()"></div>
</div>
Running the above code there is no error in browser console but it's not rendering the chart at all. I don't know what is wrong in my code. When I try to place function's code directly inside directive, it's working.
.directive('sparklineBar', function(){
return {
restrict: 'A',
link: function(scope, element) {
$('#stats-bar').sparkline([6,4,8,6,5,6,7,8,3,5,9,5,8,4,3,6,8], {
type: 'bar',
height: 45,
barWidth: 3,
barColor: '#fff',
barSpacing: 2
})
}
}
})
I don't want to use the above way as I need multiple charts. Please help me fix this using controller functions.
It is better to move the function logic into service/factory then using Injection to be used in your directive.
Example:
app.factory('sparkService', function () {
var ss = {} ;
ss.slBar= function(id, values, height, barWidth, barColor, barSpacing) {
$('.'+id).sparkline(values, {
type: 'bar',
height: height,
barWidth: barWidth,
barColor: barColor,
barSpacing: barSpacing
});
};
return ss;
}
While in directive
.directive('sparklineBar', ['sparkService',function(sparkService){
return {
restrict: 'A',
scope: {
slBar: '&'
},
link: function(scope, element) {
sparkService.slBar('stats-bar', [6,4,8,6,5,6,7,8,3,5,9,5,8,4,3,6,8], '45px', 3, '#fff', 2);
}
}]);

Is it possible to combine kinetic.js and backbone.js?

I want to code an app that simply puts a rectangle on the screen. But I need to combine kinetic.js and backbone.js for this and i am not sure it can be done.
Kinetic code is:
document.getElementById('rect').addEventListener('click', function() {
rect = new Kinetic.Rect({
x: 239,
y: 75,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
offset: [50,25],
draggable: true,
});
And backbone code
$(function() {
var Shape = Backbone.Model.extend({
defaults: { x:50, y:50, width:150, height:150, color:'gray' },
setTopLeft: function(x,y) { this.set({ x:x, y:y }); },
setDim: function(w,h) { this.set({ width:w, height:h }); },
isCircle: function() { return !!this.get('circle'); }
});
*I added .html file these paths
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<script type="text/javascript" src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.3.3.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.2.2/underscore-min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.5.3/backbone-min.js"></script>
All i want to place kinetic part instead of default values in backbone. Is it possible?
With your help, we wrote this example of work which puts a rectangle on the screen using both kinetic.js and backbone.js. I wish it would be useful for who is looking for this kind of integrated code.
Thanks a lot for your help!
var KineticModel = Backbone.Model.extend({
myRect: null,
createRect : function() {
alert("rectangle created.");
var rect=new Kinetic.Rect({
x: 10,
y: 10,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 1,
offset: [0, 0],
draggable: true,
});
return rect;
}
});
var KineticView = Backbone.View.extend({
tagName: 'span',
stage: null,
layer: null,
initialize: function (options) {
model: options.model;
el: options.el;
this.layer = new Kinetic.Layer();
this.stage = new Kinetic.Stage({ container: this.el, width: 400, height: 400 });
this.stage.add(this.layer);
},
events: {
'click': 'spanClicked'
},
render: function () {
var rect = this.model.createRect();
this.layer.add(rect);
this.stage.add(this.layer);
alert("render");
},
spanClicked: function () {
}
});
var kModel = new KineticModel({});
var kView = new KineticView({ el: '#container', model: kModel });
$('#shapetest').click(function() {
kView.render();
});
Yes this is definitely possible. I would just create a model that stores the data that you will be using in your shape, use a view to render a span tag with click me, attach an event listener to the span and then output the rectangle when the user clicks.
var ShapeModel = Backbone.Model.extend({});
var rectangle = new ShapeModel({
x: 10,
y: 10,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
offset: [0, 0],
draggable: true,
});
var RectangleView = Backbone.View.extend({
tagName: 'span',
initialize: function (options) {
model: options.model;
el: options.el;
},
events: {
'click': 'spanClicked'
},
render: function () {
this.$el.text('click me');
},
spanClicked: function () {
var stage = new Kinetic.Stage({
container: this.el,
width: 200,
height: 200
});
var layer = new Kinetic.Layer();
var rect = new Kinetic.Rect(this.model.toJSON());
layer.add(rect);
stage.add(layer);
}
});
var rectangleView = new RectangleView({ el: '#shapetest', model: rectangle });
rectangleView.render();
I would upgrade to the latest version of Backbone and Underscore too.
Also, thanks for pointing out Kinetic. Hopefully it has support for drawing on the canvas on a mobile device.

Categories

Resources