I am trying to edit the edges/triangulation of a planebuffer geometry in three js.
Example of problem
I want to change the corners in red to be triangulated like the corner in green.
Is this possible via editing a plane, or do I have to start building my own custom mesh buffer.
Here is a fiddle for an example of the kind of manipulation I am doing on the plane. (can click and drag to rotate it)
var camera, scene, renderer;
var geometry, material, mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.z = 5;
scene = new THREE.Scene();
geometry = new THREE.PlaneBufferGeometry( 10, 10, 10, 10 );
const pointLight = new THREE.PointLight(0xFFFFFF, 1);
const ambientLight = new THREE.AmbientLight(0xFFFFFF, 0.1);
pointLight.position.y += 2;
pointLight.position.x = -1;
scene.add(pointLight);
scene.add(ambientLight);
const grid = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0],
[0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0],
[0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0],
[0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0],
[0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
const planePos = geometry.attributes.position;
for (let x = 0; x < grid.length; x++) {
const row = grid[x];
for (let y = 0; y < row.length; y++) {
const h = row[y];
const i = (x * row.length) + y;
planePos.setZ(i, h * 0.5);
}
}
//
material = new THREE.MeshPhongMaterial({flatShading:true});
mesh = new THREE.Mesh( geometry, material );
mesh.rotateX(Math.PI * -0.5);
mesh.translateZ(-1);
scene.add( mesh );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
}
function animate(t) {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
body {
margin: 0;
}
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
Ok, as #prisoner849 commented, buffergeometryies index property was the answer.
I redid the triangulation of the mesh by looping over the "squares" of my mesh, getting their corners and then changing the indexes for each squares triangles to one of a pre calculated set, based on which corner had a unique height. It also seems that you want the indexes to go in a specific order to control which side is "up", it seems to be that counter clockwise or so.
const size = 10;
const vertMap = [0, 3, 1, 3, 2, 1];
const triSets = [
[0, 3, 2, 0, 2, 1],
[1, 3, 2, 1, 0, 3],
[0, 3, 2, 0, 2, 1],
[1, 3, 2, 1, 0, 3],
];
const getSquareVerts = (x, y) => {
const i = (y * size) + x + y;
return [i, i + 1, i + (size + 2), i + (size + 1)];
}
const getUniqueHeightPoint = (verts) => {
let unique = -1;
const set = verts.reduce((p, n) => {
const c = p[n.toString()] || 0;
p[n.toString()] = c + 1;
return p;
}, {});
const keys = Object.keys(set);
if (keys.length == 2 && (set[keys[0]] == 1 || set[keys[0]] == 3)) {
for (const key of keys) {
if (set[key] == 1) {
unique = verts.findIndex((v) => v == parseFloat(key));
break;
}
}
}
return unique;
}
const reworkTris = (plane) => {
let indexOffset = 0;
const planeIdx = plane.geometry.index;
for (let y = 0; y < this.size; y++) {
for (let x = 0; x < this.size; x++) {
const verts = this.getSquareVerts(x, y);
const heights = verts.map((v) => this.planePos.getZ(v));
const uniqueHeight = this.getUniqueHeightPoint(heights);
let tris = vertMap.map((i) => verts[i]);
if (uniqueHeight >= 0) {
tris = triSets[uniqueHeight].map((i) => verts[i]);
}
planeIdx.set(tris, indexOffset);
indexOffset += 6;
}
}
planeIdx.needsUpdate = true;
}
const plane = new THREE.Mesh(new THREE.PlaneBufferGeometry());
reqorkTris(plane);
I am trying to create an area chart that looks like this where I am using bars:
var trace1 = {
x: ['2013-10-04 9:00:00', '2013-10-04 9:30:00', '2013-10-04 10:00:00', '2013-10-04 11:00:00', '2013-10-04 11:30:00', '2013-10-04 12:30:00'],
y: [20, 20, 10, 10, 20, 20],
type: 'bar',
base: [5,5,5,5,5,5],
mode: 'none'
};
var data = [trace1];
myDiv = document.getElementById('myDiv');
Plotly.newPlot(myDiv, data);
Pen
As you can see y axis starts from non zero value. Is it even possible?
Thanks
You can add this code to start y-axis 0
var layout = {
yaxis: {
rangemode: 'tozero' //or below
//range: [0, 25]
}
};
Plotly.newPlot(myDiv, data, layout);
My Animated.View has the following style:
{
transform: [
{
scale: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [initialScale, 1]
})},
{
translateX: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [startX, endX]
})},
{
translateY: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [startY, endY]
})},
]
}
When initialScale is 1 and the animation starts, I see the expected behavior: Animated.View starts at (startX, startY) and linearly moves to (endX, endY). However, when initialScale is 0.5 for example, the starting point of the view is not (startX, startY), the movement is not linear (a bit spheric) and the end point is still as expected - (endX, endY).
How can I scale my View while keeping a linear movement and expected start position?
Like the user #ArneHugo pointed out in the comments, the non-linear movement can be solved by positioning the full-size container element and scaling another element within it.
The position of the element is not as expected, because the origin for the scale transform is the center point of the element. React Native doesn't (yet) support specifying the transform origin, but if the width and height of the scaled element are known in advance, it's easy to calculate the offset as follows:
const width = 100;
const height = 20;
const scale = {
transform: [
{
scale: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [initialScale, 1]
})
}
]
};
const position= {
transform: [
{
translateX: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [startX - (width / 2) - (width * initialScale / 2), endX]
})
},
{
translateY: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [startY - (height / 2) - (height * initialScale / 2), endY]
})
}
]
};
return (
<Animated.View style={position}>
<Animated.View style={[styles.thing, scale]} />
</Animated.View>
);
I've solved this problem by using scale factor for positioning:
imageScale = new Animated.Value(1);
imageX = new Animated.Value(0);
imageX = new Animated.Value(0);
...
<Animated.Image source={item} style={[styles.image, {
transform:[
{scale: this.imageScale},
{translateX: Animated.divide(this.imageX,this.imageScale)},
{translateY: Animated.divide(this.imageY,this.imageScale)},
]
}]}/>
If you use interpolation, this looks a bit complicated but the idea remains the same:
transform: [
{
scale: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [initialScale, 1]
})},
{
translateX: Animated.divide(
this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [startX, endX]
}),
this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [initialScale, 1]
})
)
}]
I am trying to make animations work in google charts. For some reason animation doesn't trigger.
Its pretty simple code. I would appreciate any help.
google.setOnLoadCallback(drawChart);
var data = google.visualization.arrayToDataTable([
['Task', 'Hours per Day'],
['Work', 11],
['Eat', 2],
['Commute', 2],
['Watch TV', 2],
['Sleep', 7]
]);
function drawChart() {
var options = {
width: 400,
height: 240,
animation:{
'duration': 5000,
'easing': 'out',
},
vAxis: {minValue:0, maxValue:100}
};
var chart = new google.visualization.ColumnChart(document.getElementById('piechart'));
chart.draw(data, options);
}
var ch=0;
function change(){
if(ch==0){
data = google.visualization.arrayToDataTable([
['Task', 'Hours per Day'],
['Work', 1],
['Eat', 20],
['Commute', 20],
['Watch TV', 20],
['Sleep', 17]
]);
ch=1;
}
else if(ch==1){
data = google.visualization.arrayToDataTable([
['Task', 'Hours per Day'],
['Work', 10],
['Eat', 2],
['Commute', 12],
['Watch TV', 24],
['Sleep', 47]
]);
ch=0;
}
drawChart();
}
full code is on below JSFIddle
https://jsfiddle.net/hjnufh0o/
You're recreating the chart object everytime you call drawChart() which has the effect of destroying the existing chart and building a new one - so there is nothing to animate between.
https://jsfiddle.net/2foeopyv/
I've pulled out the declarations for chart and options from the drawChart() section, so its now updating the chart rather than trying to recreate it.
I am doing my first interactive visualization using dc.js. I have come to a hard stop over a dc.barChart() attribute that I cannot seem with the answers I find here og on google. I will start the code from the crossfilter()function. I am able to create dc.rowCharts() so I highly doubt that it is a malformed .json problem
var ndx = crossfilter(salgsTransaksjonene);
//Define Dimensions
var kundeDim = ndx.dimension(function(d) { return d["CustomerName"]; });
//Calculate metrics
var OmsetningKunder = kundeDim.group().reduceSum(function(fact) { return fact.TotalAmount;});
//Charts
var toppChart = dc.barChart("#topp-20-bar-chart");
toppChart
.width(950)
.height(240)
.margins({top: 10, right: 50, bottom: 30, left: 50})
.dimension(kundeDim)
.group(topp20OmsetningKunder)
.transitionDuration(500)
.elasticY(true)
.yAxis().ticks(4)
When it comes to the .x() attribute I have tried the following
// .isOrdinal(true)
// .xUnitCount(20)
.xUnits(dc.units.ordinal.domain(salgsTransaksjonene.map(function (d) {return d.CustomerName; })))
.x(d3.scale.ordinal());
// .isOrdinal(true)
// .xUnitCount(20)
.xUnits(dc.units.ordinal)
.x(d3.scale.ordinal());
The errors I get is mostly the same; Uncaught TypeError: undefined is not a function
and various combinations of the above attributes, but to no avail. Any Ideas about what could be wrong is greatly appreciated!
Try to add a .domain with your ordinal values like this.
Also I've seen the order of the declarations to be of importance.
.x(d3.scale.ordinal().domain(['cat1','cat2','cat3']))
.xUnits(dc.units.ordinal)
here is a full working barchart for your inspiration.
chart11
.width(xxx)
.height(xxx)
.margins(xxx)
.dimension(xxx)
.group(xxx)
.x(d3.scale.ordinal().domain([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
.xUnits(dc.units.ordinal)
.centerBar(false)
.transitionDuration(transitionDuration)
.elasticY(true)
.gap(1)
.renderHorizontalGridLines(true)
.yAxis().ticks(2)
;