THREE.js & the order of transformations - javascript

I'm learning THREE.js right now, and I stucked with a probably noob problem.
I've a JSON object width dynamic update, it contains some data of 4 walls. The JSON struct:
{
...
walls: [{
start: {
x : 0,
y : 0,
z : 0
},
length: 1200,
rotation: 0
}, {
start: {
x : 0,
y : 0,
z : 0
},
length: 1200,
rotation: -(Math.PI/2)
}, {
start: {
x : 0,
y : 0,
z : 1200
},
length: 1200,
rotation: 0
}, {
start: {
x : 1200,
y : 0,
z : 0
},
length: 1200,
rotation: (Math.PI/2)
}],
...
}
I'm trying to position walls on canvas, It's OK when the wall has just a translation OR rotation, but there's a problem when the wall has both of them.
Here's my code (this._container is an instance of THREE.Mesh):
this._container.matrixAutoUpdate = false;
this._container.add(new THREE.AxisHelper(1000));
if(rotation) {
this._container.rotation.y = rotation;
this._container.updateMatrix();
}
if(translation) {
this._container.translateX((translation.x + (width/2)));
this._container.translateY((translation.y + (height/2)));
this._container.translateZ((translation.z));
this._container.updateMatrix();
}
If I apply rotation first then translate, it rotates the object's local axes too, and the translation will have wrong directions (http://robber.hu/webgl/1.png). If I apply translation first, than rotate, the Y axis moves to other position, and the rotation will be around wrong point (http://robber.hu/webgl/2.png).
I think there are two ways to solve this problem, but can't find the solutions:
Somehow using a "global translation", so the object translates on the scene's axis, and then use the first method
Change the object's "pivot" to left or right edge, and than use the second method
How can I implement it, or where can I find some docs/tutorial for this?

Solved.
The solution was that: Use three transformations insted of two. First, translate object to final position, second, rotate it, and finally, translate again via local X and y axis. Third translation moving the local axis from object's center to the corner.
R

Related

Is there a way to calculate custom label position on a Highcharts Activity Gauge?

I have a Highcharts activity gauge that has two series. I am trying to place labels at the starting point of each ring. I have it working with hardcoded x,y coordinates, but I'm wondering if there is a way to calculate the location instead. It looks like this currently:
Here is the code I am using to add the labels in the chart render event:
function render() {
var chart = this;
chart.renderer.label('Completed 65%', 24, 25, 'rect', 0, 0, true, true, '')
.add();
chart.renderer.label('Follow-up 45%', 28, 42, 'rect', 0, 0, true, true, '')
.add();
}
I'd like to calculate the x,y values in the chart.renderer.label() function instead of hardcoding them to 24,25 and 28,42. However, I have not been able to find anything in the object model to locate the physical location of the series starting x and y, or the size of the label. I have many of these activity gauges to complete and going through them all and trying to find the magic coordinates seems like the wrong approach.
You can follow the same approach as icons rendered in the official Activity gauge demo here: https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/demo/gauge-activity/
There you will find position calculated using series point shapeArgs. I modified that function to render labels as you expected. Check it in the demo posted below.
Function code:
function renderLabels() {
var offsetTop = 5,
offsetLeft = 5;
if (!this.series[0].label) {
this.series[0].label = this.renderer
.label('Completed 65%', 0, 0, 'rect', 0, 0, true, true)
.add(this.series[1].group);
}
this.series[0].label.translate(
this.chartWidth / 2 - this.series[0].label.width + offsetLeft,
this.plotHeight / 2 - this.series[0].points[0].shapeArgs.innerR -
(this.series[0].points[0].shapeArgs.r - this.series[0].points[0].shapeArgs.innerR) / 2 + offsetTop
);
if (!this.series[1].label) {
this.series[1].label = this.renderer
.label('Follow-up 45%', 0, 0, 'rect', 0, 0, true, true)
.add(this.series[1].group);
}
this.series[1].label.translate(
this.chartWidth / 2 - this.series[1].label.width + offsetLeft,
this.plotHeight / 2 - this.series[1].points[0].shapeArgs.innerR -
(this.series[1].points[0].shapeArgs.r - this.series[1].points[0].shapeArgs.innerR) / 2 + offsetTop
);
}
Function invocation:
chart: {
type: 'solidgauge',
events: {
render: renderLabels
}
}
Demo:
https://jsfiddle.net/BlackLabel/vpj32tmy/

How do I transition an object's attribute in d3?

I would like to apply a transition, not on a d3 selection, but on a js Object.
Something like
var node = {
x : 0,
y : 0,
radius : 100
};
d3.transition(node).duration(200).attr('radius', 200);
Any suggestions please?

How I can set maximum value at graphael y axis and why?

I have several points that I try to represent using a graphael line chart. Almost all of them are below 0.03. However, the chart sets 1 as the maximum and all points are shown to be very down at the chart. When I have even one point over 0.03, graphael sets the maximum value something more than 0.03 and therefore the chart displays correctly. What can I do for the rest cases where all my points are below 0.03? It is really very ungly, and not helpful at all.
Is there a way to set the max value of the y axis automatically?
If you cannot help me, can you please run it, just to tell me if he can run it normally? It wouldn't take much time...
This is what I mean
I noticed that it also might produce very wrong y axis labels...
My code is shown below
var lines = r.linechart(30, 30, 600, 440,[[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71]],[[0.02046,0.00635,0.02813,0.02808,0.02385,0.00729,0.02145,0.01978,0.02683,0.03006,0.03105,0.01211,0.0083,0.0022,0.02172,0.01541,0.01181,0.02418,0.00552,0.02708,0.01011,0.0105,0.0294,0.00132,0.00615,0.02303,0.00065,0.00967,0.00381,0.02167,0.01357,0.0221,0.02512,0.00918,0.01072,0.01083,0.00598,0.00195,0.01716,0.00347,0.03058,0.01815,0.02899,0.01537,0.0241,0.0241,0.00451,0.00088,0.01574,0.00688,0.0143,0.0024,0.03047,0.02876,0.00528,0.00996,0.00865,0.02681,0.02194,0.00082,0.00664,0.01178,0.01596,0.00516,0.0165,0.00895,0.01869,0.03082,0.02318,0.01089,0.00943,0.00986]], {axisxstep : 12,axisystep : 5,nostroke: false, axis: "0 0 1 1", symbol: "circle", smooth: true }).hoverColumn(function () {
this.tags = r.set();
for (var i = 0, ii = this.y.length; i < ii; i++) {
this.tags.push(r.tag(this.x, this.y[i], this.values[i], 160, 10).insertBefore(this).attr([{ fill: "#fff" }, { fill: this.symbols[i].attr("fill") }]));
}
}, function () {
this.tags && this.tags.remove();
});

How to find the offset for a polygon Fabric.js

I am making a polygon from lines.
x = options.e.pageX - offset.left;
y = options.e.pageY - offset.top;
On click, I capture mouse position. After, I add that point to array of points.
roofPoints.push(new Point(x, y));
function Point(x, y) {
this.x = x;
this.y = y;
}
When all points are set I do this:
var roof = new fabric.Polyline(roofPoints, {
fill : 'purple',
});
The problem with this is that while I set points I am drawing lines for the polygon like so:
var points = [ x, y, x, y ];
lines.push(new fabric.Line(points, {
strokeWidth : 1,
selectable : false,
stroke : 'red'
}).setOriginX(x).setOriginY(y));
So basically I'm making a counter of a polygon and when I'm done drawing the counter, I just create a polygon. But the problem is that when I create polygon it doesn't fit in the counter it just moves away from the counter. I have tried to find how to correctly offset it.
roof.set({
left : left,
top : top,
});
I was trying to get left upper point of a bounding rectangle for the polygon and to set it so it places correctly. But that din't work. This how it looks
And a fiddle How it looks
Ok so I checked coords of created polygon and saw that it has recalculated them somehow and that's why it was offset. For example:
PointBefore
58 | 193
PointAfter
-189 | -52
This is how it changes, so to make the correct offset all I did was get it before I create the polygon and set top and left after it has been created.
var left = findLeftPaddingForRoof(roofPoints);
var top = findTopPaddingForRoof(roofPoints);
var roof = new fabric.Polyline(roofPoints, {
fill: 'purple'
});
roof.set({
left: left,
top: top
});
return roof;
And a fiddle that works.
This script doesn't work on 1.4.13 and 1.5.0 fabricjs versions. Cannot confirm on previus versions.
EDIT: Fixed the problem, also in later versions:
Change this:
var points = [ x, y, x, y ];
lines.push(new fabric.Line(points, {
strokeWidth : 1,
selectable : false,
stroke : 'red'
}).setOriginX(x).setOriginY(y));
into this:
var points = [ x, y, x, y ];
lines.push(new fabric.Line(points, {
strokeWidth : 1,
selectable : false,
stroke : 'red'
}));

many very confusing problems with kinetic.js

i got some problems with understanding kinetic.js (the documentation is horrible for newbies...) i hope i can explain it with my bad english.
Problem 1: Everytime when i #reset my canvas it is not really resetting it. its more like its pushing another background image over the actual canvas and when i click on it it jumps back to the original...
function clearCanvas() {
context.clearRect(0, 0, 1000, 1000); //whole canvas
context.drawImage(buehneObj,0,0); //redraw the main background image
}
and call it with:
reset = document.getElementById('reset');
document.getElementById('reset').onclick =function(){clearCanvas();
}
Problem 2: the slider i build for scaling the image is not working at all but i dont see the problem... ...the variables are global and if i test alert it i see that values are existing...
standard jquery slider:
$('#scaleslider').slider({
animate: "fast",
step: 0.1,
value: 1,
min: 0.1,
max: 1,
slide: function(event,ui){groesse = ui.value} //global variable
});
i made it hidden(display:none) and on click "block"
var scaleslider = document.getElementById('scaleslider').style;
document.getElementById('resize').onclick =function(){ scaleslider.display ="block";}
and here's how kinetic parts look like (dragMotiv is my first start image) "groesse" is the variable for my x and y slider value(they can us the same so it scales correct):
var dragMotiv = new Kinetic.Image({
image: imageObj,
x: 250,
y: 300,
width: 330,
height: 263,
rotationDeg: 0,
scale: { x:groesse, y:groesse },
draggable: true,
dragBoundFunc: function(pos) {
var newY = pos.y < 290 ? 290 : pos.y > 305 ? 305 : pos.y;
var newX = pos.x < 250 ? 250 : pos.x > 390 ? 390 : pos.x;
return {
x: newX,
y: newY
};
}
});
Problem 3: Saving is not possible at all.
i uploaded it to my server to let you guys take a look at it. i know that there is one little thingy that i just dont see(i hope so).
http://manufaktur13.de/playground/canvas_kinetic.html
I think you should not clear the canvas, instead you should keep record what you have drown and remove those items, and redraw the layer.

Categories

Resources