I am building a workflow tool that renders with d3js. I initially created the tool in an "editor" mode, where users can drag and manipulate nodes and dependencies within a workflow. Now I am having a hard time rationalizing the proper way to make my current draw procedure support "view" and "edit" modes and stay DRY.
My initial code is basically one long draw procedure:
Define JS prototypes
Create initial d3js grid (zoom/pan grid)
Function(s): Define menu system
Function: Draw dependencies (svg groups in d3js)
Function: Draw nodes (svg groups in d3js)
Get data, iterate & instantiate, iterate and draw dependencies, iterate and draw nodes
Adding switch logic within each of the functions where mode-behavior or SVG structure differs seems like the road to spaghetti-code.
It feels equally wrong to have 3 independent procedures for each mode - but I'm starting to think that having a distinct "draw" procedure for each mode is more flexible way to go about having 3 modes.
Maybe I'm thinkin' about this all wrong. Maybe I should render everything in read-only mode first and then apply any "edit" or "monitor" mode behaviors or visual additions afterwards.
What's the best way to support multiple similar, but different draw procedures in a DRY fashion?
Related
I'm working on an application for generating a path for custom-made CNC machine. It is based on a PLC controller which does not support G-code, therefore I need to define the whole path as a list of commands.
I'm having a trouble with defining the toolpath for pocket milling. As an input, I use DXF files with different kind of shapes in it. Each shape is located on different layer and built of simple elements such as LINE, ARC etc. What I need is to analyze these simple elements as a closed contour and generate toolpath for milling the whole material inside this contour. Do you know of any library or simple algorithm where I can define the shape (in this case, based on the DXF data) and the lib/algorithm would generate the whole toolpath, taking the tool diameter into consideration?
For simple shapes like circles or rectangles, I'm able to generate such toolpath manually but when the shape is more complex (e.g. like below) I'm running out of ideas how to do so.
There is a lot of freeware CAM software in the internet and each of them generates the toolpath in form of G-Code, so I assume such kind of algorithm is implemented there somehow. I thought about using such CAM software but the G-code output is not usable for me, besides I do not need any GUI. Most of them is also written in higher-level languages whilst I'm writing my app in JavaScript running under node.js.
Do you mean you know how to process each entity individually and don't know how to combine them together? Since they touch you just need to find the next entity according to its starting/ending point (1), from the current entity's ending point. And if the point (1) was an ending point of that entity, you will need to process the found entity in reverse, or process it in normal order and reverse the resulting line. Of course taking care to offset it in the correct direction.
For faster neighbor search sort them first by either X or Y coordinate of both their starting and ending points.
I want to make object to become highlighted when selected in order to do this I need a custom shader that scales that renders the model outline - this part of the task I'm familiar with - XML3D provides a way to implement custom shader.
But the missing piece is having access to render pipeline:
Its impossible to make nice highlighting without copying the model and painting it over old one
or rendering the scene in two passes (postprocessing).
Creating another model copy in the usual way (attaching new element to dom tree) won't solve the issue since I need also control scene blending.
How to I get it done with with xml3d?
Is it possible without digging deep into the library?
In general there are four approaches to implement highlighting:
you can exchange materials back and forth (not very efficient)
you can use material overrides for highlighted objects, which will adapt one or more parameters of the current shading (e.g. emissive color)
you can use a custom shader in combination with an arbitrary uniform attribute which indicates that the object should be highlighted. In the shader, you can adapt color and rendering based on the attribute. E.g. you could do a rim-highlighting or a wireframe rendering. Here is an example for a shader that colors an object if the uniform selected has a specific value.
For instance:
<mesh id="foo">
<data src="mesh-data.json"></data>
<float name="selected">0</float>
</mesh>
To highlight this object: $("#foo float[name=selected]").text("1");
you can adapt the rendering pipeline to render the highlighted object twice and blend it in various ways
If sufficient for your use-case, I would recommend approach 3, as it is not very intrusive. The interface for creating custom rendering pipeline is not yet very stable.
As ksons mentioned the render pipeline interface is undergoing some major changes right now, XML3D 4.8 is the last version that supports it in its current form. Version 5.0 will likely re-introduce it in a (hopefully) much improved form.
We use a custom render pipeline in one of our internal projects to draw a wireframe overlay onto selected models, I've posted a simplified version of this pipeline as a Gist for you to have a look at. Essentially it renders the scene using the standard internal render pass and then does a second pass to draw the highlighted objects in a crude wireframe mode without depth testing.
As I said this works in v4.8, if you need this functionality in v4.9 then please open an issue and I'll see about re-enabling it as a minor release.
I'm playing around with different ways of integrating D3 and Angular, in the context of learning both of these frameworks, and am hoping for some input:
My client application receives a JSON array of nodes and an array of edges from my server.
The central component of the client is a graph visualization implemented as a D3 force-directed layout: For each node in the nodes array, a (SVG) circle element is added to this visualization, and lines between these circles are added for each edge in the edges array.
Of course, D3's selection.data( ) makes it trivial to add these elements and bind each to the data it represents, but the graph visualization is only part of a much larger application: I need to create different types of elements representing these same nodes and edges in different parts of the application (which D3 has nothing to do with), and I'd like to keep all of these elements bound to a single dataset.
My primary goal is minimizing code complexity, and - although I've fallen in love with the simplicity and elegance of D3's data-binding functionality - I've arrived at the tentative conclusion that using it in one part of the application while using Angular to do the same in other parts is creating unnecessary complexity, and that the simplest approach would be to use Angular to handle the data-binding/element-creation
In other words, instead of using selection.data( ).enter( ).append( ) to create SVG elements, I'm thinking I should do so using a ng-repeat="node in nodes", perhaps creating each as a custom directive to allow for custom functionality. Having done so, I would then need to get these elements "into" D3, i.e. managed by its force-directed layout.
Is my reasoning here sound? In particular, I'm worried that I'm overlooking complications this will create with regard to object constancy, which is an important requirement as nodes will be entering, exiting and moving about the screen constantly and I need these transitions to be smooth. How would you recommend I go about integrating my angular-created elements into D3 (more precisely, getting them into my force.nodes{ } and force.links( ) arrays) to avoid any such complications?
Finally, I'm also considering a strategy that I'm hoping might give me the best of both worlds: I could use D3 to create my SVG elements and bind them to their respective datum, but rather than executing that code in the link function of visualization directive (as I've been doing, and as all the Angular/D3 tutorials I've found do), I could run it in the compile function, and do something like this:
d3.select('SVG')
.selectAll('.node')
.data('nodeDataArray')
.enter( )
.append('circle')
.attr("class", "node-icon"); //...other attributes/styles etc
where node-icon is the normalized name of a directive with a restrict property that includes C. If this runs in the compile method, angular should then compile all of these directives as normal, adding any additional functionality / interfaces with other directives (etc.), the same way it does with any other type of element. Right?
This is the option I'm most attracted to intuitively - are there any pitfalls of it I might be overlooking, which might make the former strategy preferable?
I have been pondering pretty much the same problem for a while and come to the following conclusion.
The simplest way to integrate Angular created elements with d3 is to add the directives with .attr and then .call the compile service on the d3 generated elements. Like this:
mySvg.selectAll("circle")
.data(scope.nodes)
.enter()
.append("circle")
.attr("tooltip-append-to-body", true)
.attr("tooltip", function(d){
return d.name;
})
.call(function(){
$compile(this[0].parentNode)(scope);
});
Here is a Plunker.
I think the idea of generating elements with Angular ngRepeat rather than d3 is working against the frameworks. D3 does not expect to be handed a bunch of elements. It wants to be handed data - almost always an array. It then has a stack of excellent functions to convert that data into various SVG or HTML elements. Let it do that.
It seems from this quote...
D3 makes it trivial to add elements and bind each to the data it represents, but the graph visualization is only part of a much larger application: I need to create different types of elements representing these same nodes and edges in different parts of the application (which D3 has nothing to do with), and I'd like to keep all of these elements bound to a single dataset.
... you are implying that generating elements with d3 somehow prevents you from binding the same data to different parts of the application. I can't see why. Just have d3 generate elements from a scope array (as is done in the linked Plunker). Then use the same dataset wherever you want in the usual Angular way. Other parts of the application can update the dataset and a $watch callback can re-render the d3 graphic.
I'm trying to build a force-directed layout, wherein the connected nodes have their own internal layout that is not simply a recursive force-directed layout (which, I believe, would be possible with the hierarchy layout). The "inner" layout would be custom, but, for illustration let's say I wanted the nodes, internally, to have a partition layout. Is this possible?
My question was really twofold:
can you pull off having more than one style of layout (for instance, a bubble graph inside a force-directed graph) in a sensible way with D3, or is D3 the wrong tool for such a thing, and
Can you use D3 layouts for each of these layouts, or do you have to do everything custom.
In the end, the design changed, and no longer called for this odd scenario. Being much more familiar with D3, though, I think I can answer.
Yes. It can be done. Each layout is its own discrete object, with its own data on which to work, and can be given its own DOM elements to populate. Creating two layouts that even shared the same data and DOM outputs would probably work, if you could manage the interaction between the two (making sure one only overrode changes from the other when desired).
What I know you can do for sure is manually manipulate anything that D3 is doing. At one point during development, actually, I did have two layouts on the same page, come to think of it. I was laying out half the graph with pre-determined x/y coordinates, and allowing the rest to be laid out by the force directed layout. That first set, the manually placed nodes, could have been placed by some other logic than pre-determined coordinates, and the functionality would have been roughly the same.
I have a dataset which is best represented by a graph. It consists of nodes of 6 or 7 different "types" with directed edges (dependencies on one another, guaranteed not to have cyclic dependencies). The dataset is essentially a template of a layered configuration, and the user needs to be able to select bits and pieces of the configuration from different layers which are desired, and have the dependent bits be brought in automatically.
The general UI need is for a user to select or un-select items from multi-select boxes (one such box for each node type), and have "depended-on" items in the other boxes become selected or unselected as needed. I need to be able to pull down the dataset from the server, let the user select the desired bits (with the dependency processing being done in javascript on the client side for responsiveness), and then submit the result back when they are finished.
The dataset is large and complex enough that actually showing it as a graph would be overwhelming and confusing to the user. Only basic graph traversal operations are needed, since all that is required is to cascade selections out the dependencies. (For example, a user un-selecting a node would result in that nodes dependencies becoming unselected if there were no other selected node which still depended on them. A user selecting a node would result in all of that node's dependencies becoming selected.) A simple depth or breadth first search following directed edges from the start node will suffice to visit all affected nodes. If I can follow edges either direction, bonus. (If not I can easily generate an edge-reversed graph and use that when needed.)
I have dug around on here and found references to a number of javascript graph visualization libraries, but most of these discussions seem to interpret "graph" as "chart" and I have no charting needs here. My digging has led me to this list: Raphael, protovis, flare, D3, jsVis, Dracula, and prefuse. From this list it looks like jsVis or Dracula might have the underlying graph constructs I need if I just ignore the visualization side, but it isn't clear to me from the documentation if that is the case. I have to rule out a few others because I cannot bring in any flash dependencies. Unfortunately I don't have time to prototype things with this many libraries. (I will be digging into jsVis and dracula more though, barring some handy input here.)
If anyone has experience with something from that list and believes that the graph portion of it can be used independently of the visualization portion, that will certainly meet my needs. If there is some other library I could use that meets my needs, that would be great too. One final requirement regarding licensing: the library needs to be "free" in a non-copyleft way - So ideally Apache v2.0, BSD, MIT, or something like that.
I haven't used it, but you might want to check out data.js. It's an MIT-licensed library with a range of data-structure utilities. In particular, it includes Data.Node and Data.Graph:
A Data.Graph can be used for representing arbitrary complex object graphs. Relations between objects are expressed through links that point to referred objects. Data.Graphs can be traversed in various ways.