Create SVGPoint inside an element with user coordinate - javascript

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.

Related

Pass Pointer to Array Element to Function

I am working on a program for a task in Linear Algebra that performs computations on vectors and matrices of floating point numbers.
i.e.,
v = [3.14159, 2.256, 1.5783, 6.782]
A = [ 9.7 2.333 5.467 5.2123
6.789 4.789 5.671 9.111
1.113 4.562 8.223 5.2125
6.666 7.8181 3.426 4.3567]
A part of the program performs the same operations on an input vector as it does on a specified row of an input matrix, handled by a function in C++. In C++, the same function can accept input of either a vector or matrix by having it accept a pointer to a specific array element; as long as the pointer arithmetic is meticulous and, knowing memory layout is row-major, it works. I am wondering if the same can be done in JavaScript.
I could write either of two functions:
i) A function that expects a vector.
Passing the vector in works.
However, passing in the matrix doesn't work.
I had hoped to pass in the pointer to, say, the first element in the second row (the element containing 6.789). Then to access the entire row by something like A[0][i]. But JavaScript doesn't like that.
ii) A function that expects a matrix.
Passing the matrix in works.
However, passing in the vector doesn't work. If I try to access the vector elements as v[0][i], JavaScript doesn't like that.
Either my syntax is incorrect, or I am trying to do something that cannot be done.
The vector and array cannot be changed in form (i.e., flattened, etc.) because the rest of the program needs them to keep their forms; the vector needs to remain a vector and the matrix needs to remain a matrix.
In JavaScript, is it possible to pass a pointer to a specific array element into a function and then, within the function, have the vector (or row of matrix) treated as just a regular array?
If not, is there a suggested work-around?
Does this do what you're after?
function doSomethingWithVectorOrMatrixRow(vectorOrMatrix, matrixRow) {
const aVector = matrixRow === undefined ? vectorOrMatrix : vectorOrMatrix[matrixRow];
return doSomething(aVector);
}
/* Use it as */ doSomethingWithVectorOrMatrixRow(v);
/* or */ doSomethingWithVectorOrMatrixRow(A, 1);
Although of course it would be more efficient to store a matrix as a flat Array, and simply operate on a given range of that Array, which would work equally well for a vector (range = whole vector), but you say you can't change the data structure used.

Chart.js 2.2.x - How to access the pixel coordinate of a point in my dataset

I'm creating a plugin for my chart (in ChartJS 2.2.2), and for that I need the pixel position of each point of my dataset.
When inspecting the chart.config.data.datasets[0]._meta[0], I get back the following object:
But when I access the x field directly in my plugin code, the values returned are different. The commands:
chart.config.data.datasets[0]._meta[0].dataset._children[0]._model.x and
chart.config.data.datasets[0]._meta[0].data[0]._model.x (which yields the same value when looking it up in the chrome debugger) both return x = 3 instead of 44.67.
Why is this happening? What is the proper way to access the pixel coordinate of a point in my dataset?
The plugin is called multiple times, I was debugging only the initial values for the coordinates. Turns out the last calls were made with the correct value for X (44.67). I think this was happening because initially the canvas containing the chart was hidden (using ng-hide), only after init it was being shown.
It was rendered correctly though.

Drawing plots interactively in a web app

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.

XML3D: generateRay

I'm implementing draggable object in XML3D and i need a help with xml3d.generateRay function, as an argument it takes two numbers, as I understand correctly those are x,y coordinates of point in projection space that ray passes through. But are those coordinates in reference to the window element (left-top corner of the browser window) or to the xml upper-left corner?
Second question: how can I get hit point from getElementByRay
Specification says differently for different versions - and since there is no spec for 4.9 I ask.
The coordinates are given in window space, so relative to the top left corner of the window.
You can get the hit point and hit normal from getElementByRay by passing two XML3DVec3 objects into the function, eg:
var hitPoint = new XML3DVec3();
var hitNormal = new XML3DVec3();
xml3dElement.getElementByRay(ray, hitPoint, hitNormal);
The function will fill the vectors with the hit point and normal in world space.

"Apply" a transformation in RaphaelJs

I've written a wrapper class around RaphaelElement. It has a property elem which stores the corresponding Element and the two convenience methods setPos and getPos. Moreover there's a position member with the two entries x and y.
Therefore getPos() merely returns the position. setPos accepts a new position as a parameter and has to update the coordinates of elem.
Unfortunately there is no information what type of RaphaelElement will be stored in elem, it could be a circle as well as a rectangle. Right now the code inside setPos looks like this:
//position is the parameter, this.pos is the member
this.pos = position;
this.elem.attr("x",this.pos.x);
this.elem.attr("y",this.pos.y);
this.elem.attr("cx", this.pos.x);
this.elem.attr("cy", this.pos.y);
This feels like a dirty workaround. It works with both circles and rectangles, but on a rectangle there's no attribute "cx" or "cy" and on a circle both "x" and "y" don't exist.
I browsed the documentation for a better way to modify the position of a RaphaelElement and found the method transform. But there's a problem: I haven't found a way to give "absolute" new coordinates to transform. It only offers means to translate, rotate or scale. If I have to change the position by applying a translation from my current position to the new position, then I have to append a new translation to the transformation string. I fear that it might grow VERY long. Moreover, I would have to evaluate an increasingly long string to get my current position.
It certainly is possible to move my Elements by appending new translations to the transformation but I would like to be able to either set the new position directly or to "apply" or "finalise" a transformation, so that it's string doesn't grow infinitely.
The consolidate method on a TransformList will convert a list of transforms into a single matrix. You could call this after you've added your translation.
Alternatively you could call getItem on the transformList which will give you an SVGTransform object and you can call setTranslate on that which would set the new position directly. You'd need to be careful that there is a transform and create one if there isn't.

Categories

Resources