Open kimardenmiller opened 10 years ago
An update on my fork .... I now have a working ForceLayout in Angular side-by-side with a working copy of yours in Backbone. In the next step I thought I would try to preserve your existing file structure (not necessarily a given considering how much changes going to Angular) and essentially move your existing code from require.js to Angular's dependency injection and a custom directive like the one used in the current Angular example.
I'm trying to decide if time is the right parameter to use for the slider. You have pointed out at least one problem (luckysunbunny) and I'm not sure that won't always be an issue. Maybe number of links is a better choice. Any thoughts on that?
Hey Kim,
Took a look at your angular fork, but unfortunately my angular and coffeescript is, er, not very good.
From a functionality point of view, the main thing that's a bit 'off' is your angular version jumps around on every tick of the time slider. Not completely sure what's going on there (need way more time to process the angular-ization), but my initial instincts are it's probably in how you emit nodes or maybe how D3 is converting them. Perhaps look to the D3 data bind and make sure that any time there are new nodes emitted, they're being joined to the correct existing DOM element (ie perhaps D3 is just creating new nodes on every tick and removing the previous ones, creating new nodes that need to find their force-equilibrium).
Regarding the time problem, it really depends on what the distribution of the variable is like. In the case of this example, the luckysunbunny comment was a far outlier on the distribution, so the filtering was to make a slider tick represent a balanced portion of the elements. If your distribution is prone to such outliers, then you might want to do some similar filtering. An alternative is to not use time but use something like posting index (1,2,3,4 instead of 8:01, 8:09, 8:11, 21:54), but that loses some of the 'bursts' that give you an intuitive sense of the chronology. In this sketch chronology was important... may be less important to your project.
Hi Dan,
Thanks for taking the time to look in on my fork. Perfect timing, actually. The jumpy rendering is my first truly D3 issue after having solved the more basic platform integration.
I cleaned up the extra files to make it easier reading. Now fireflies/
contains all your original code in CoffeeScript and fireflies-ng/
contains the Angular version in three files: controller.coffee
, services.coffee
, and directive.coffee
following Angular convention.
Basically, controller.coffee
is your main.js and services.coffee
pretty much contains all your other files and objects, except directive.coffee
which is your ForceView.js.
Later today I'll start looking line by line to see what is different in terms of the returned objects from emitting, but so far I have not seen any difference. It may be I have some things to learn about what Angular does in directives in terms of reusing the svg.
Update: I've refined the console logging a bit, made sure the slider emits exacts the same, etc. ...
Where would I look for the joining to see if existing svg elements are getting joined correctly? In the fireflies-ng/directive.coffee
beginning at line 128 with scope.render = ( nodesAndLinks ) ->
is where Angular does what you called @update() in your code. It reads:
scope.render = ( nodesAndLinks ) ->
scope.visSvg.selectAll('*').remove()
if (!nodesAndLinks)
console.log "No data present."
return
console.log 'ng nodesAndLinks in render', nodesAndLinks
nodes = nodesAndLinks.nodes
links = nodesAndLinks.links
#scope = this
fvID = scope.id
# -------------------
# Update the nodes...
scope._nodes = scope.visSvg.selectAll("circle.node").data(nodes, DATA_JOIN_ON_ID).style("fill", @_colorNode)
....
scope.
= @
As far as D3 goes, does that all seem wired up correctly?
Solved it. It was this line above:
scope.visSvg.selectAll('*').remove()
Not quite sure how you are cleaning up the dom between restarts, but I added some reset logic to do it when the slider gets back to zero.
Now on to adapting things to Spokenvote.
Thanks, @dlopuch :exclamation: ... happy 4th :us:
Hi Dan,
I'm moving on now to make some modifications for the SV application. The first one is using an a user's image rather than a colored circle. I'm able to do it in a force layout here, but not on in the Fireflies example. Seems it might have something to do with how the node is referred to?
scope.visSvg = d3
.select(element[0])
.append("svg:svg")
. . .
scope._nodes = scope.visSvg.selectAll("circle.node")
.data(nodes, DATA_JOIN_ON_ID)
. . .
enterNodes = scope._nodes.enter()
.append('svg:circle').each (d) ->
Any chance you can see what I need to do to replace svg:circle with a link to an image?
Seems as if images would have been simple, but I guess images step outside of official svg objects. Finally got it working here. There were a few ways to go, but ended up with a clipping path to make the circle. Hope Bostock would approve. :grimacing:
Next:
Hey Dan, I finally have the work live on bl.ocks. If you look closely you will see how the forking actually works, where voters have to give up their previous vote when they change their mind on a given topic.
Any final thoughts?
Moved it to this bl.ocks.
Dan,
I'm fascinated by your Fireflies Force Layout project. Don't think it's the layout you suggested for Spokenvote's vote forking, but what do you think about our applying Force Layout to vote forking? I'm envisioning the nodes mapped to the voter's profile picture and then showing how the final top-voted proposal was forked and evolved over time.
Ideally we'd want to show both user votes and proposals as different (nodes?), since in Spokenvote users retain ownership of votes but not proposals. It might also be really valuable to make dominance (highest number of votes on a proposal) more obvious since that's the final objective of using Spokenvote.
Would really value your input. The visualization of forking for non-programmers is exactly what seems to be our project's current obstacle. :beetle:
/kim