I try to set the rotation of an object at it's own axis using:
object.rotateOnAxis(new THREE.Vector3(1,0,0) , Math.PI)
in the render function, but the object is rotating in every rendering. Is there a way to set the rotation at it's own axis like when using:
object.rotation.x = Math.PI
or
object.rotation.set(Math.PI,0,0)
to set the rotation at the world axis?
Just remove the following code from the render method.
object.rotateOnAxis(new THREE.Vector3(1,0,0) , Math.PI)
You could put it to the declaration of object. Surely, you could also set the rotation there (in render) but that would reduce the performance needlessly.
Simply put it outside the render function.
EDIT: You can simply use
object.rotation.x += rotationSpeed;
in the render method to let it rotate.
If the rotation must take place at the render function that means that the model is changing rotation at every render. Simply find the rotation difference and apply it to the model using the code mentioned:
object.rotateOnAxis(new THREE.Vector3(1,0,0) , Math.PI);
Store the old rotation and the new rotation at variables and apply the difference:
var old_rotation = value1;
var new_rotation = value2;
var Drotation = value1-value2;
if the difference is negative or positive it shows the direction of the rotation so just apply:
object.rotateOnAxis(new THREE.Vector3(1,0,0) , Drotation);
UPDATE:
The simplest way i found is:
object.rotateX(angle);
object.rotateY(angle);
object.rotateZ(angle);
this rotates the object around its axes :D
Related
I do not know how to set the position of a instance in gd script. The instanced shows up on the corner of the screen.
Thanks :)
It depends on what type of instance. If it's an object that has been derived from something like a Node2D, then position.x or position.y should do it. Do you have any code we can look at?
Depends on whether you want 2D or 3D.
A common method is as such:
Create the object you want to instance in its own scene.
Save the object as a scene (.tscn file) - for example "Scene1.tscn"
Call upon your instanced scene from your main scene as follows:
Make sure to preload the scene you plan to instance before your ready() function. For example if was called "Scene1", then declare :
onready var Scene1 = preload("res://Scene1.tscn")
Then, later in your code when you want to call an instance of the scene, do it as such:
var InstancedScene = Scene1.instance()
add_child(InstancedScene)
// This simply instances the scene (I think at co-ordinates (0,0,0)), but you can tell it where to instance it using the following example:
For 3D use:
InstancedScene.transform.origin = Vector3(50.0, 0.0, -50.0)
//Gives position x=50, y=0, x=-50.
This can also be used for rotation, just specify transform.basis and give a similar Vector3 coordinate set.
OR for 2D use:
InstancedScene.position = Vector2(100.0, 100.0)
//This instances the object 100 pixels across and 100 pixels down. Sub in whatever values you need. You can also specify a rotation using InstancedScene.rotation_degrees = 45 (To give 45 degrees for example)
How would I go about changing the registration point of a movieclip labeled "tablet" placed on the stage (root) dynamically?
For example: I have the following:
var tablet = this.tablet; //movieclip labeled "tablet" on stage
function resetTablet(){
tablet.regX = tablet.width/2; //move registration point to center
tablet.regY = tablet.height/2;
}
However when I call it using GSAP:
var tl = new TimelineLite();
tl.to(tablet, 1, {alpha:1, onComplete:resetTablet})
.to(tablet, 3, {alpha:0, scaleX:1.5, scaleY:1.5})
the registration point is still set to the upper left corner rather than the center.
What am I doing wrong here? Thanks!
Registration points affect change both the transformation point, but also the position. If you set a displayobject that is 100x100 pixels to regX=50;regY=50, then it will draw from that point, moving the content 50px to the top and left. If you make that change you should also translate the clip to x=50;y=50.
An issue with you example is that there is no width or height on EaselJS content (explained here). You can get the bounds of anything generated by Flash CC using the nominalBounds property, which Flash exports as a property on every object. If you have multiple frames, you can turn on "multi-frame bounds" in the publish settings, and a frameBounds property is added to the objects as well.
Note that nominalBounds and frameBounds are not used by the getBounds method.
Here is how you might be able to approach it.
var bounds = tablet.nominalBounds;
tablet.regX = bounds.width/2;
tablet.regY = bounds.height/2;
// Optional if your actual registration point was [0,0] before:
tablet.x += tablet.regX;
tablet.y += tablet.regX;
Hope that helps.
The following code works on Chromium :
var node = window.d3.selectAll('#L1 > *:nth-child(2)');
var bbox = node.node().getBBox();
console.log(bbox) // {height: 44, width: 44, y: -13, x: 144}
but not with nodejs + jsdom:
"TypeError: Object [ PATH ] has no method 'getBBox' "
M. Bostock pointed out that JSDOM doesn't support getBBox()
What D3js replacement to use to get the bounding box of #L1 > *:nth-child(2) ?
Past efforts lead me there : getBBox() based fiddle
Path's bounding box
Digging straight into the element's path data d="..." should work. An svg line is basically a set of x,y points. Assuming absolute coordinates without translation nor big bezier curves, which is the case of my D3js-generated svg lines, I'am finding in this data the min and max values for both x and y.
To do so, I get the d="..." svg line or multilines code. For simplicity sake, I rudely removes possible relative jumps such h30 or v20 since I never saw any in my D3js output, then clean out letters (aka svg commands : M,L,H,V,C,S,Q,T,A,Z), simplify the spaces and line jumps, then split by the remaining spaces. I get a clean arrays of coordinates.
Important to note, my selector directly target a single non-translated path.
var getBBox = function(selector){
var xmin, xmax, ymin, ymax,p;
// clean up path
var t = d3.select(selector).attr("d"); // get svg line's code
console.log(t)
t = t.replace(/[a-z].*/g," ") // remove relative coords, could rather tag it for later processing to absolute!
.replace(/[\sA-Z]+/gi," ").trim().split(" "); // remove letters and simplify spaces.
console.log(t)
for(var i in t){ // set valid initial values
if(t[i].length>1){
p = t[i].split(",");
xmin = xmax = p[0]; ymin = ymax = p[1]; }
}
for(var i in t){ // update xmin,xmax,ymin,ymax
p = t[i].split(",");
if(!p[1]){ p[0]=xmin; p[1] = ymin;} // ignore relative jumps such h20 v-10
xmin = Math.min(xmin, p[0]);
xmax = Math.max(xmax, p[0]);
ymin = Math.min(ymin, p[1]);
ymax = Math.max(ymax, p[1]);
} return [[xmin,ymax],[xmax,ymin]]; // [[left, bottom], [right, top]] as for https://github.com/mbostock/d3/wiki/Geo-Paths#bounds
}
var bb = getBBox("path");
JSfiddle DEMO
Groups bounding boxes
For groups of multiple paths, you may want to traverse the svg DOM to loop upon each single path of the group in order to update xmin, ymin, xmax, ymax.
Translated elements
To handle translated elements, adapt further.
Alternatives
Other better approaches may exist. Remember to check if getBBox() and getBoundingClientRect() are available in your context, since they are native and very convenient.
The reason why getBBox/getBoundingClientRect/getClientRect does not work in NodeJS+JSDOM is that calculating these values of an SVG (or HTML) element involves massive amounts of computation.
First, all CSS code in <style> elements must be parsed (which is already not trivial). Then the CSS selectors, cascading and inheritance rules must be applied to know what size, position or line width an element has. And even after you know all style property values, you need to do some non-trivial maths to calculate the bounding boxes: definition of different SVG transform functions, compositions of these, bounding boxes of SVG primitives and Bezier curves. Browsers support all of these (they have to, in order to draw the element), but JSDOM is simply not meant for all of these.
But fortunately, canvg is a JavaScript implementation of most of SVG, which uses a <canvas> element to draw the image. It does support most of the above, and although it does not have an interface for giving you those data, fortunately it has very nice (and MIT licensed) code, so hopefully you can copy and reuse parts of it. As of now, the code is written in a single file, and it has CSS parsing, applying cascading rules, path data parsing, definitions of SVG transforms, applying transformations, and bezier curve bounding box calculation. That is, almost everything you need to calculate bounding boxes :) It does not, however, support CSS selectors, but it can reuse another library. But unfortunately, as far as I can tell, canvg is not ready for running in NodeJS, you probably need some tweaks.
There is, however canvgc, an SVG to JS compiler, which contains an older version of canvg, and it is capable of running in NodeJS. So it is easier to start with that.
I'd like to create choropleth map of Czech Republic. Inspired by this article http://bl.ocks.org/mbostock/4060606, I have created this
http://jsfiddle.net/1duds8tz/2/
var width = 960;
var height = 500;
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
var offset = [width / 2, height / 2];
var projection = d3.geo.mercator().scale(6000).center([15.474, 49.822]).translate(offset);
var path = d3.geo.path().projection(projection);
queue().defer(d3.json, "..map.geojson").await(ready);
function ready(error, reg) {
var group = svg.selectAll("g").data(reg.features).enter().append("g");
group.append("path").attr("d", path).attr("fill", "none").attr("stroke", "#222");
}
When I tried to fill svg path with some color, I ended on this
http://jsfiddle.net/1duds8tz/3/
group.append("path").attr("d", path).attr("fill", "red").attr("stroke", "#222");
There are odd values in path d attribute.
My GeoJSON data must be somehow faulty but I can't figure what is wrong.
Everything looks right here: https://gist.github.com/anonymous/4e51227dd83be8c2311d
Your geoJSON is corrupted and as a result your polygons are being drawn as the interiors of an infinitely bounded polygon. That's why when you attempt to give a fill to the path, it goes beyond the extent of the screen but still displays the border just fine. I tried to reverse the winding order of your coordinates array, and that seemed to fix all of them except for "Brno-venkov", which might be the source of your problems (especially given its administrative shape).
I'd suggest going back to where you created the original GeoJSON and try to re-export it with simplification. If you want to reverse the coordinates on your GeoJSON to correct the winding order, that's pretty simple:
geodata = d3.selectAll("path").data();
for (x in geodata) {geodata[x].geometry.coordinates[0] = geodata[x].geometry.coordinates[0].reverse()}
But this won't fix the problem polygon, nor will not reversing its coordinates.
In case you are familiar with svg manipulation you can try geojson2svg. This allows you manipulate svg in standard way but you have to code a little more. In case your application requires d3 for many other purpose then d3 is best solution.
I've got exactly the same problem with Mapzen's .geojson files.
.reverse()-ing isn't good enough, if you can't make sure all your data has the same winding order.
I solved it with this one:
https://www.npmjs.com/package/geojson-rewind
You'll need to have npm & require available
Install it, and save it to your project
npm i -g geojson-rewind
Import it, to make it useable
var rewind = require('geojson-rewind');
Use it on the data, in this case:
req = rewind(req);
Tip: If you are working with static data, you can do this only once on the console, and you're good to go.
I am trying to move (translate) an object that has been rotated, when I move (translate) the rotated object it loses it's rotation and does move correctly. If the use the same code on an object that is not rotated then the move correctly. What I am doing wrong here?
Here is a fiddle
This code loses the rotation.
var part = s.select("#part_2");
var t = new Snap.Matrix();
t.translate(part.getBBox().x,part.getBBox().y+18);
part.transform(t);
I'm not sure what order you want the transforms to apply. If you want the squares to move such that down is applied after transforming i.e. down for the rotated matrix is at an angle you'd do this...
var t = part.transform().localMatrix;
t.translate(0, 18);
part.transform(t);
If, however you want down to always be down then you'd do something like this...
var t = new Snap.Matrix();
t.translate(0, 18);
t.add(part.transform().localMatrix);
part.transform(t);
The trick is to get the existing matrix for the shape and append/prepend the transform you want to it.