I am basically trying to encapsulate the functionality from rkirsling's blocks inside an Enyo object so that I can reuse it. I started by removing global variables and switching them out for published attributes. I am able to get the balls to show, but they are all rendered in one spot and there are no other functionalities. I can't add more balls or draw lines from one to the other.
My thoughts are that I am doing something incorrectly in restart()
. I left the majority of the code in jsfiddle since I don't want a massive wall of code, but I've copied what I believe to be the important parts.
Edit: It looks like tick()
is the issue. The way I am referencing path
and circle
seems to be the issue.
enyo.kind({
name: "D3Block",
published: {
// mouse event vars
selected_node: null,
selected_link: null,
mousedown_link: null,
mousedown_node: null,
mouseup_node: null,
svg: "",
path: "",
circle: "",
links: [],
nodes: [],
colors: null,
force: null,
drag_line: null,
lastNodeId: 0
},
initialize: function(clientContainer){
this.inherited(arguments);
var width = 500,
height = 500;
this.colors = d3.scale.category10();
this.svg = d3.select(clientContainer)
.append('svg')
.attr('width', width)
.attr('height', height);
// set up initial nodes and links
// - nodes are known by 'id', not by index in array.
// - reflexive edges are indicated on the node (as a bold black circle).
// - links are always source < target; edge directions are set by 'left' and 'right'.
this.nodes = [
{id: 0, reflexive: false},
{id: 1, reflexive: true },
{id: 2, reflexive: false}
]
this.lastNodeId = 2;
this.links = [
{source: this.nodes[0], target: this.nodes[1], left: false, right: true },
{source: this.nodes[1], target: this.nodes[2], left: false, right: true }
];
// init D3 force layout
this.force = d3.layout.force()
.nodes(this.nodes)
.links(this.links)
.size([width, height])
.linkDistance(150)
.charge(-500)
.on('tick', this.tick())
// define arrow markers for graph links
this.svg.append('svg:defs').append('svg:marker')
.attr('id', 'end-arrow')
.attr('viewBox', '0 -5 10 10')
.attr('refX', 6)
.attr('markerWidth', 3)
.attr('markerHeight', 3)
.attr('orient', 'auto')
.append('svg:path')
.attr('d', 'M0,-5L10,0L0,5')
.attr('fill', '#000');
this.svg.append('svg:defs').append('svg:marker')
.attr('id', 'start-arrow')
.attr('viewBox', '0 -5 10 10')
.attr('refX', 4)
.attr('markerWidth', 3)
.attr('markerHeight', 3)
.attr('orient', 'auto')
.append('svg:path')
.attr('d', 'M10,-5L0,0L10,5')
.attr('fill', '#000');
// line displayed when dragging new nodes
this.drag_line = this.svg.append('svg:path')
.attr('class', 'link dragline hidden')
.attr('d', 'M0,0L0,0');
// handles to link and node element groups
this.path = this.svg.append('svg:g').selectAll('path');
this.circle = this.svg.append('svg:g').selectAll('g');
// app starts here
this.svg.on('mousedown', this.mousedown())
.on('mousemove', this.mousemove())
.on('mouseup', this.mouseup());
// d3.select(window)
// .on('keydown', this.keydown())
// .on('keyup', this.keyup());
this.restart();
},
tick: function() {
console.log("TICK TICK");
var svg = d3.select(this.clientContainer.hasNode());
console.log(svg);
var path = this.path;
var circle = this.circle;
// if(!path || !circle){return};
path.attr('d', function(d) {
var deltaX = d.target.x - d.source.x,
deltaY = d.target.y - d.source.y,
dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
normX = deltaX / dist,
normY = deltaY / dist,
sourcePadding = d.left ? 17 : 12,
targetPadding = d.right ? 17 : 12,
sourceX = d.source.x + (sourcePadding * normX),
sourceY = d.source.y + (sourcePadding * normY),
targetX = d.target.x - (targetPadding * normX),
targetY = d.target.y - (targetPadding * normY);
return 'M' + sourceX + ',' + sourceY + 'L' + targetX + ',' + targetY;
});
circle.attr('transform', function(d) {
return 'translate(' + d.x + ',' + d.y + ')';
});
}
});
I suspect that your use of tick is supposed to be as a callback. You probably want to use
enyo.bind()
. Right now, you're passing the return value of tick to the 'on' event.