Drawing plots interactively in a web app - javascript

I am looking for a library preferably in JavaScript, that will allow a user to draw a plot (simple one consisting of vertical and horizontal steps) like this one:
The idea is that when the user is done with the plot I can generate data points from the graph and process them.
I don't know where to start, I am looking to start learning to do this within a JS based framework (meteor) but I can't find a library that allows for something like this. The closest library I found is d3.js but I couldn't find any example that allows for this.
Would anyone be able to point out to me a sample example to start from? Would you know of a better suited library to accomplish what I am asking for?

Here is a relatively simple fiddle which accomplishes some of what you asked for, excluding axis (which are relatively easy and has plenty of examples). It uses D3 for all the drawing and mouse event handling. On click it simply executes svg.append("circle").attr("r", 5), and if it's not the first click (i.e. linking points) then it also will create a path element using the previous mouse click coordinates:
svg.insert("path", "circle").attr("d", function () {
return [
"M", prevClickLoc[0], prevClickLoc[1],
"L", prevClickLoc[0], y,
"L", x, y].join(" ");
})
Where x and y are the current mouse coordinates. Also has an export button that will output a list in the form of cx,cy,cx,cy,... :: d,d,d,d,.... On import, you could easily split this array into two using indexOf("::") or whatever you choose if you want to change the formatting. Then just exectue for (x in circles) {svg.append("circle").attr("cx", function...).attr("cy", function...);} and do something similar for paths for (y in paths) {svg.append("path").attr("d", function(){return paths[y];});}. It would be even easier if on export you made the cxcy array in the format cx;cy,cx;cy since then you could simply split the array at each comma and then split each index of the resulting array at the semicolon for a nice nested array.
Small update in this version, you can only place points if the current mouse x is greater than the previous x coordinate, and it also has the line d3.event.stopPropagation(); which prevents accidental highlighting of the page.

Related

How to apply transformation to selection in Illustrator by scripting

I managed to select every thing I want in Illustrator with a ExtendScript Toolkit javascript code: lots of things (text, path, symbols, ...) in several layers. Now I want to resize them the same way, then move them.
I know how to apply a transformation to one object by code, but I want to avoid looping on each element because it would be very very long and transformation would be applied from the anchor point of each element, so my drawings wouldn't be cohesive.
So, I am looking for a way to do like in Illustrator UI: right click > transform > scale. Is there any UI command like this I could access from code (javascript)?
There are at least three ways to do this:
Record AI Actions that perform required transformations, and then play these Actions (by DoScript) from your script
Group selected objects and apply required transformations to the group as #Dane proposed. You need to backup the Layer object property to allow objects to be restored in original layers, as shown in VBA example below:
For i = Index_Lo To Index_Hi
Call Layers_Backup.Add(Item:=SelectedItems(i).Layer, Key:=Format(i))
Call SelectedItems(i).Move(Temp_Group, AiElementPlacement.aiPlaceAtEnd)
Next i
Call Temp_Group.Resize(scaleX:=120, scaleY:=120, changeLineWidths:=120)
For i = Index_Lo To Index_Hi
Call SelectedItems(i).Move(Layers_Backup(Format(i)), AiElementPlacement.aiPlaceAtEnd)
Next i
Call Windows API functions (like PostMessage (..., WM_COMMAND, ..., ...), SendDlgItemMessage, FindWindowEx etc) to show, fill and execute required AI transformations dialog boxes
IMHO, item #1 is the easiest to implement while item#2 is the most reliable
So I dont know if you can get away with not looping in some form or other. that said, if you dont mind putting your selection in to a group, it might be faster to loop through your selection adding to a group which might be faster than looping and through the selection and scale and moving each element. With the group object you can then do groupObject.scale() and .translate().
Here is a snippet i took from a script of mine.
#target "illustrator"
var aiApp = app.activeDocument;
var aSelection = aiApp.selection;
var aGroup = app.activeDocument.groupItems.add();
for (i=0; i < aSelection.length; i++){
aSelection[i].move( aGroup, ElementPlacement.INSIDE);
aSelection[i].move( aGroup, ElementPlacement.PLACEATEND);
}
//moves up 700 points and scales by 200
aGroup.translate(0,700)
aGroup.resize(200, 200, true , true, true, true, 200)

Find 'view' co-ordinates in vis.js

I'm working on a modification to vis.js's Graph3d to do a filled line graph, like this:
The hard part - unsurprisingly - is working out the rendering order for the polygons. I think I can do this by checking whether a ray from the viewer to a given line B crosses line A:
In this example, since line A is "in the way" of line B, we should draw line A first. I'll use a snippet of code from How do you detect where two line segments intersect? to check whether the lines cross.
However, I haven't figured how to find the position of the user's view. I kind of assumed this would be the camera object, so wrote a little bit of debug code to draw the camera on the graph:
var camera = this._convert3Dto2D(this.camera.getCameraLocation());
ctx.strokeStyle = Math.random()>0.5 ? 'ff0000' : '00ff00';
ctx.beginPath();
ctx.moveTo(camera.x, camera.y);
ctx.lineTo(camera.x, camera.y+5);
ctx.stroke();
In fact, the camera co-ordinates as measured by this are always at 0,0,0 on the graph (which would be the far top right on the above screengrab). What I need, I think, is effectively the bottom of the screen.
How can I find this? Or is there a better way to achieve what I'm trying to do?
I don't know if this is still an active issue, but FWIW, Graph3D has internal handling of the sort ordering.
All graph points are sorted with respect to the viewpoint, using a representative coordinate called point.bottom. The rendering is then done using this ordering, with the most distant elements drawn first. This works fine as long as none of the elements intersect; in that case, you can expect artefacts.
Basically, all you need to do, is define point.bottom per graph polygon, and Graph3D will then pick it up from there.
If you are still interested in working on this:
This happens in Graph3d.js, method Graph3d.prototype._calcTranslations(). For an example, have a look at how the Grid and Surface graph elements are initialized in Graph3d.prototype._getDataPoints(). The relevant code is:
obj = {};
obj.point = point3d;
obj.trans = undefined;
obj.screen = undefined;
obj.bottom = new Point3d(x, y, this.zRange.min);

Create SVGPoint inside an element with user coordinate

I have a small project (to learn SVG) running (using javascript).
I would like to be able to track a point in a shape with its own user coordinate system. My idea is to find the coordinates of the point within the shape, then create an SVGPoint, so that I can pass on that element. I have seen the method create SVGPoint in examples, but it seems it is used in the context of the 'SVG_root' (that is, document.documentElement.createSVGPoint() works).
When I use (in Firefox)
inSvgObj.createSVGPoint()
where inSVGObj is a element, the web console says "TypeError: inSvgObj.createSVGPoint is not a function". Is it possible to create an SVG point within the to subsequently set with values representing coordinates in that 's user coordinate system?
EDIT (after considernig Robert Longson's answer):
Given that SVGPoint is created only within an "SVG root" and that I have been unable to find a way to move that to within another element, I have found more convenient to use a different svg element type: SVGMatrix. In case it helps someone (as I have spent some time trying to deal with this),It is possible to manipulate analogue values inside an SVG Point by creating an SVGMatrix that would work as a simulated point (for the purposes of coordinates. To that endthe methods .createSVGMatrix(), getCTM() and.multiply() (this last from SVGMatrix) are used. To illustrate that, I will include a (js) function that takes 4 arguments: x-coordinate in user coordinate system (ucs) to transform, y-coordinate is that ucs, object whose ucs is the want we want to transform and an object in the ucs we want to transform to; and returns am object with thrre poperties the x-coordinate in the transformed ucs, its y-coordinate and 1 (for consistency with SVG Recommendations).
function coorUcsAToUcsB(ucsAx,ucsAy,svgObjUcsA,svgObjUcsB){
var ctmUcsA=svgObjUcsA.getCTM();
var ctmUcsB=svgObjUcsB.getCTM().inverse();
var mtx=document.getElementsByTagName('svg')[0].createSVGMatrix();
mtx.e=ucsAx;
mtx.f=ucsAy;
var simulSvgP=ctmUcsB.multiply(ctmUcsA.multiply(mtx)); //1
return {"x":simulSvgP.e,"y":simulSvgP.f,"z":1};
}
//1 this line creates an svg matrix with 1st and 2nd column at 0, 3rd with coordinates of ucsB from the analogue svg matrix with coordinates in ucsA - it takes the coordinates in ucsA to viewport's cs and from there to coordinates in ucsB. For the matrix operation explanation, see this.
Any comments, in particular having overlooked a existing method that does the same or any drawbacks, will be more than welcome.
You create the SVG Point using the root element creation but once you've done that you can set whatever values in it you want. When you assign those values to an object the object will interpret them in its coordinate system.

Spatial Data Structure for Games

I need to implement a spatial data structure to store rectangles then be able to find all rectangles that intersect a given rectangle. This will be implemented in JavaScript.
So far I am developing a Quad Tree to cut down the search space but because it is for a game, all objects that move will need to update its position in the tree. Back to square one.
Are there any data-structures or methods to help? It will need to process around 10,000 objects so brute force isn't good enough.
A hash table works fairly well as an approximate intersection test. Hash tables are used as part of a more sophisticated algorithm for detecting collisions in ODE.
Logically, this test divides the space into a regular grid. Each grid cell is labeled with a list of objects that intersect that cell. The grid is initialized by scanning all objects. I don't know javascript, so I'll use python-ish pseudocode.
for each ob in objects:
for each x in [floor(ob.x_min / grid_size) .. floor(ob.x_max / grid_size)]:
for each y in [floor(ob.y_min / grid_size) .. floor(ob.y_max / grid_size)]:
hashtable[hash(x, y)].append(ob)
To find collisions with a given object, look up near-collisions in the hash table and then apply an exact collision test to each one.
near_collisions = []
for each x in [floor(ob.x_min / grid_size) .. floor(ob.x_max / grid_size)]:
for each y in [floor(ob.y_min / grid_size) .. floor(ob.y_max / grid_size)]:
near_collisions = near_collisions ++ hashtable[hash(x, y)]
remove duplicates from near_collisions
for each ob2 in near_collisions:
if exact_collision_test(ob, ob2):
do_something
You can still use quadtree even if you have moving objects – just remove and reinsert an object every time it moves or every time it crosses region boundary.
But quadtrees aren't very good at storing rectangles and I would recommend using an R-tree instead.

How can I stop elements overlapping using JavaScript and the Raphael JavaScript library

I’m generating multiple, random sized, circular elements using the Raphael JavaScript library but because it’s random a lot of the circular elements being generate overlap or cover each other. What I wanted to know, is there any way with JavaScript to tell if one element is in already in particular position so to avoid the overlapping? Essentially, I want to create random elements on a canvas, of a random size that don’t overlap or cover each other.
There's a couple of test files I created here to give you an idea of what I'm doing. The first one generates random objects and the second link sets them to a grid to stop the overlapping.
http://files.nicklowman.co.uk/movies/raphael_test_01/
http://files.nicklowman.co.uk/movies/raphael_test_03/
The easiest way is to create an object and give it a repulsive force that degrades towards zero at it's edge. As you drop these objects onto the canvas the objects will push away from each other until they reach a point of equilibrium.
Your examples aren't working for me, so I cannot visualize your exact scenario.
Before you "drop" an element on the canvas, you could query the positions of your other elements and do some calculations to check if the new element will overlap.
A very simple example of this concept using circle elements might look like this:
function overlap(circ1, circ2) {
var attrs = ["cx", "cy", "r"];
var c1 = circ1.attr(attrs);
var c2 = circ2.attr(attrs);
var dist = Math.sqrt(Math.pow(c1.cx - c2.cx ,2) + Math.pow(c1.cy - c2.cy, 2));
return (dist < (c1.r + c2.r));
}
var next_drop = paper.circle(x, y, r);
for (var i in circles) {
if (overlap(next_drop, circles[i])) {
// do something
}
}
Of course calculating just where you're going to place a circle after you've determined it overlaps with others is a little more complicated.

Categories

Resources