not able change textures on click threejs - javascript

i am trying to change textures / colors of an object onclick (by clicking on separate cubes )
I'm able to change the color of an object only once (even though i use a for-loop ) and provided that no previous textures or colors on the object.
However, I'm not able to change the color if the object already has an existing color.
Do i need to add some needsUpdate ? I did but no luck.. please have a look on my onclick function.
EventsControls.attachEvent('onclick', function() {
var colors = ['White', 'blue', 'gold'];
for (var i = 0; i < colors.length; i++) {
object.traverse(function(child) {
if (child instanceof THREE.Mesh) {
if (child.material.name == "Sofa_Leather") {
child.material = colors[i]; // array elements are already defined
child.material.needsUpdate = true;
child.material.buffersNeedUpdate = true;
child.material.uvsNeedUpdate = true;
child.receiveShadow = true;
}
}
})
}
});
Kindly let me know where 'im going wrong. Thank you.
//retried but could manage to change only one color with the below code, i think im using the needsUpdate in a wrong way.
var index=0;
var colors=[0xfffeef,0xffff00,0x000fff];
object.traverse( function( child ) { if ( child instanceof THREE.Mesh ) {
if (child.material.name == "Sofa_Leather") {
if(index == colors.length) index = 0;
child.material.color.setHex(colors[index++]);
child.material.needsUpdate = true;
child.receiveShadow = true;
} }
})

I believe you can do this by using:
material.color.setHex(0xffffff * Math.random()); // set to random color
EDIT:
Well yeah sure you can do this also:
var colors = [0xff0000, 0x00ff00, 0x0000ff]; // red, green and blue
if(index == colors.length) index = 0;
line.material.color.setHex(colors[index++]);
See this updated jsfiddle

Related

Check if a set of objects intersect another set of objects

I have an object(LineA) that is composed of 4 children and sub-children. They are Meshes(MeshLineMaterial) and ArrowHelpers. Then I have another set of objects(Other Lines) of the same kind.
Sample object:
castShadow: false
children: Array(2)
0: ja {uuid: "B883597B-392D-41EB-A306-33A2F065A5B1", name: "PathA", type: "Mesh", parent: Hc, children: Array(0), …}
1: tb {uuid: "8B507A56-437C-47C5-9A0A-43DE9D8DE0D4", name: "", type: "Object3D", parent: Hc, children: Array(2), …}

length: 2
__proto__: Array(0)

frustumCulled: true
layers: Pf {mask: 1}
matrix: U {elements: Array(16)}

matrixAutoUpdate: true
matrixWorld: U {elements: Array(16)}

matrixWorldNeedsUpdate: false
nObjType: "Path"

name: "Path"

parent: wd {uuid: "20293B1F-868F-4A06-9A24-AF14738955A8", name: "", type: "Scene", parent: null, children: Array(121), …}

position: n {x: 0, y: 0, z: 0}
quaternion: ua {_x: 0, _y: 0, _z: 0, _w: 1, 
_onChangeCallback: ƒ}
receiveShadow: false
renderOrder: 0
rotation: Qb {_x: 0, _y: 0, _z: 0, 
_order: "XYZ", 
_onChangeCallback: ƒ}
scale: n {x: 1, y: 1, z: 1}
selectable: true
type: "Group"
up: n {x: 0, y: 1, z: 0}

userData: {}
uuid: "CC27818D-5EEE-4A89-A39C-7F56C8C8F9BB"
visible: true
eulerOrder: (...)
id: 561
modelViewMatrix: U {elements: Array(16)}
normalMatrix: Y {elements: Array(9)}
useQuaternion: (...)

__proto__: B

I am trying to create a system where when I create LineA, it shouldn't collide/cross with Other Lines.
I have tried the bounding box and raycaster:
function collision()
{
var originPoint = LineA.position.clone();
var bb=new THREE.BoxHelper(LineA, 0x00ff00);
bb.geometry.computeBoundingBox();
var collidableMeshList = OtherLines;
for (var vertexIndex = 0; vertexIndex < bb.geometry.attributes.position.array.length; vertexIndex++)
{
var ray = new THREE.Raycaster( bb.position, bb.geometry.attributes.position.array[vertexIndex] );
var collisionResults = ray.intersectObjects( collidableMeshList );
if ( collisionResults.length > 0)
{
console.log("true");
hit = true;
}
}
}
I tried referring to this example
function detectCollisionCubes(bb, Line2bb){
bb.geometry.computeBoundingBox(); //not needed if its already calculated
Line2bb.geometry.computeBoundingBox();
bb.updateMatrixWorld();
Line2bb.updateMatrixWorld();
var box1 = bb.geometry.boundingBox.clone();
box1.applyMatrix4(bb.matrixWorld);
var box2 = Line2bb.geometry.boundingBox.clone();
box2.applyMatrix4(Line2bb.matrixWorld);
return box1.intersectsBox(box2);
}
None of them seems to be working in my case.
They show no error.
Any help would be greatly appreciated.

OpenLayers 2.13.1: deleting a geometry from a multigeometry feature

For example I have a multipolygon consisting of two polygons. I can delete vertices with the modifyFeature control and the delete-key. However, the modifyFeature control does not allow me to delete a polygon completely because it has to contain at least 3 vertices. How do I delete a polygon completely from a multipolygon feature (with the delete-key)? Is there an appropriate control or a plugin available for OpenLayers?
I tried it myself with patching the control but that resulted in multiple minor bugs. So I thought I ask first if someone already did that before I spend a lot of time to fix the issues.
removeComponent: function(point) {
var removed = this.components && (this.components.length > 3);
if (removed) {
//remove last point
this.components.pop();
//remove our point
OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,
arguments);
//append copy of first point
var firstPoint = this.components[0];
OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,
[firstPoint]);
//bm extension: possibility to delete geometry from multigeometries
} else if (this.components && this.parent && this.parent.parent && this.parent.parent.CLASS_NAME === "OpenLayers.Geometry.MultiPolygon") {
//polygon with hole
if (this.parent.components.length > 1) {
for (var i = 0; i < this.parent.components.length && this.parent.components.length > 1; i++) {
if (this.parent.components[i].id === this.id) {
OpenLayers.Util.removeItem(this.parent.components, this.parent.components[i]);
this.parent.clearBounds();
return true;
}
}
}
//seperate polygon
for (var i = 0; i < this.parent.parent.components.length && this.parent.parent.components.length > 1; i++) {
if (this.parent.parent.components[i].id === this.parent.id) {
OpenLayers.Util.removeItem(this.parent.parent.components, this.parent.parent.components[i]);
this.parent.parent.clearBounds();
return true;
}
}
}
return removed;
},

Re-size circle using paperJS

I am trying to re-size a circle using papeJS but since i used two onMouseDrag function it if conflicting. I am unable to create it. Can anyone help me. Here is the fiddle with circle
Here is the code.
<script type="text/paperscript" canvas="canvas">
var raster = new Raster({
source: 'Chrysanthemum.jpg',
position: view.center
});
var path = null;
var circles = [];
var isDrawing = false;
var draggingIndex = -1;
var segment, movePath;
var resize = false;
project.activeLayer.selected = false;
function onMouseDrag(event) {
if (!isDrawing && circles.length > 0) {
for (var ix = 0; ix < circles.length; ix++) {
if (circles[ix].contains(event.point)) {
draggingIndex = ix;
break;
}
}
}
if (draggingIndex > -1) {
circles[draggingIndex].position = event.point;
} else {
path = new Path.Circle({
center: event.point,
radius: (event.downPoint - event.point).length,
fillColor: null,
strokeColor: 'black',
strokeWidth: 10
});
path.removeOnDrag();
isDrawing = true;
}
}
;
function onMouseUp(event) {
if (isDrawing) {
circles.push(path);
}
isDrawing = false;
draggingIndex = -1;
}
;
function onMouseMove(event) {
project.activeLayer.selected = false;
if (event.item)
event.item.selected = true;
resize = true;
}
var segment, path;
var movePath = false;
function onMouseDown(event) {
segment = path = null;
var hitResult = project.hitTest(event.point, hitOptions);
if (!hitResult)
return;
if (hitResult) {
path = hitResult.item;
if (hitResult.type == 'segment') {
segment = hitResult.segment;
} else if (hitResult.type == 'stroke') {
var location = hitResult.location;
segment = path.insert(location.index + 1, event.point);
path.smooth();
}
}
movePath = hitResult.type == 'fill';
if (movePath)
project.activeLayer.addChild(hitResult.item);
}
</script>
First, your code (on jsfiddle) does not run.
The paperjs external resource returned a 404. https://raw.github.com/paperjs/paper.js/master/dist/paper.js works for paperjs.
The raster source was for a local file, not a URI.
In onMouseDown, project.hitTest references an undefined hitOptions.
It seems from your question that you want to be able to drag the circle segments to resize the circle, and you tried using two onMouseDrag functions to do that, which would not work. Instead, both operations should be in the same onMouseDrag, using if-then-else to choose between them. To make this work as expected, the item that was hit should be stored in onMouseDown instead of whatever circle your code finds at the beginning of onMouseDrag. For example, here onMouseDrag can either "move" or "resize" (jsfiddle here):
<script type="text/paperscript" canvas="myCanvas">
var raster = new Raster({
source: 'http://i140.photobucket.com/albums/r10/Array39/Chrysanthemum.jpg',
position: view.center
});
var circles = [];
var hitItem = null;
var currentAction = null;
function onMouseMove(event) {
project.activeLayer.selected = false;
if (event.item) {
event.item.selected = true;
}
}
function onMouseDown(event) {
hitItem = null;
var aColor = new Color('black');
for (var i = 0; i < circles.length; i++) {
circles[i].fillColor = aColor;
}
view.draw();
var hitResult = project.hitTest(event.point);
for (var i = 0; i < circles.length; i++) {
circles[i].fillColor = null;
}
view.draw();
if (!hitResult) {
return; //only happens if we don't even hit the raster
}
hitItem = hitResult.item;
if (circles.indexOf(hitItem) < 0) {
var newCircle = new Path.Circle({
center: event.point,
radius: 2,
strokeColor: 'black',
strokeWidth: 10
});
hitItem = newCircle;
circles.push(hitItem);
currentAction = 'resize';
return;
}
if (hitResult.type == 'segment') {
currentAction = 'resize';
} else if (hitResult.type == 'stroke') {
hitItem.insert(hitResult.location.index + 1, event.point);
hitItem.smooth();
currentAction = 'resize';
} else if (hitResult.type == 'fill') {
currentAction = 'move';
}
}
function onMouseDrag(event) {
if (!hitItem) {
return;
}
if (currentAction == 'move') {
hitItem.position = event.point;
} else if (currentAction == 'resize') {
if ((event.downPoint - event.point).length >= 1) {
hitItem.fitBounds(new Rectangle(event.downPoint, event.point), true);
}
}
};
</script>
<canvas id="myCanvas"></canvas>
Also note:
In onMouseDown, the function returns if !hitResult, so you do not need to test if (hitResult) right after that return.
Naming variables the same as objects makes searching more difficult, e.g., in your code path is an instance of Path.
Using the same variable for different purposes makes code more difficult to parse, e.g., in your code path is used to create new circles as well as to store which circle has been selected.
You have multiple variables defined twice: path, movePath, and segment.
If a variable will only be used in a single function, e.g., movePath and segment, then it makes the code more readable if the variable is defined in that function. Also, movePath is only used in a single if-statement, which just adds items back to the layer, but the only items not in the layer have been removed when the circle was originally drawn. Since those items cannot be hit, the item that was hit must already be in the layer.
The variable segment is not used.
It makes the code flow/read better if the functions are ordered logically. In this case, onMouseMove should go first because it happens before the button is clicked. Then onMouseDown goes next because it must happen before the other actions. Then onMouseDrag, and finally onMouseUp.
Instead of creating new circles in onMouseDrag and then throwing them away on the next drag, it makes more sense to create one in onMouseDown if there was no item hit, or if the hit item is not a circle. Then in onMouseDown, you just resize that circle. Path.scale or Path.fitBounds can be used for such resizing.
Instead of using multiple boolean variables to keep track of the current action (e.g., resize vs move), it is more logical to have a single variable keeping track of the current action.
Instead of your code to find whether the point is within a circle, the code I am using temporarily sets the circles' fillColor, do the hitTest, and then clears the circles' fillColor. I did this because when you hit a stroke, the shape of the circle changes, for which your code to find the draggingIndex does not account.

Changing the draw attributes of a vector feature in open layers

I am loading a shapefile from a server and than drawing it n OpenLayers. The shapefile contains over 400,000 multipolygons with varying opacity. I need to set the opacity and fill color yet openlayers seems to be ignoring it and just drawing orange squares instead. I console.log() before I change the attributes and after and it shows what I assigned it. Can anyone tell me why it is doing that?
var green = {
fill: true,
fillColor: "#006633",
fillOpacity: 1
};
var features = wkt.read(element);
if (featureNumber == 0){
document.getElementById('result').innerHTML=element;
}
features = element.toString();
var bounds;
var b = features.indexOf('MULTIPOLYGON', 0);
var c = features.indexOf('MULTIPOLYGON', 40);
if (c == -1) {
c = element.indexOf(':',b+1);
}
leftovers = features.substring(c,100000000000000000);
features = features.substring(b,c);
features = wkt.read(features);
if(features) {
if(features.constructor != Array) {
features = [features];
}
for(var i=0; i<features.length; ++i) {
if (!bounds) {
bounds = features[i].geometry.getBounds();
} else {
bounds.extend(features[i].geometry.getBounds());
}
}
pointLayer.addFeatures(features);
console.log(pointLayer.features[featureNumber].attributes );
pointLayer.features[featureNumber].attributes = green;
console.log(pointLayer.features[featureNumber].attributes );
featureNumber++
map.zoomToExtent(bounds);
var plural = (features.length > 1) ? 's' : '';
console.log('Feature' + plural + ' added');
console.log('feature number: '+featureNumber)
if (leftovers.indexOf('MULTIPOLYGON',0) != -1) {
parseWKT(leftovers,shapefile);
}
} else {
final(leftovers, shapefile);
}
}
well the style belongs in the .style property not the .attributes of the feature. You'll also need to call redraw() if it's already on the map.
pointLayer.features[featureNumber].style = green;
pointLayer.redraw();
If you want to start out with the default style and just change a few things, you can do something like this:
var green = OpenLayers.Util.applyDefaults(green, OpenLayers.Feature.Vector.style['default']);
green.fill = true;
green.fillColor = "#006633";
green.fillOpacity = 1;
pointLayer.features[featureNumber].style = green;
pointLayer.redraw();

Javascript memory leak deleting Raphael path objects

I have a memory leak in my code and I cannot figure out what is causing it. I am receiving target data from a WebSocket which contains basically an ID and an X,Y coordinate. The data is passed to a HandleData function which creates a circle for each target and a line (which is updated) to show where the target has moved from/to.
If a target no longer appears in the WebSocket stream it is removed. On testing I have found the webpage quickly amasses hundreds of mb of data in spite of me removing these items. Upon using Chrome's memory profiler it seems Raphael (or something) is holding onto all the path information in spite of me deleting it.
If anyone can help me in anyway I would be very grateful. It does seem that Raphael is holding onto the data but there is every chance I have made a mistake somewhere in my code :)
var arrayColours = ["#f33", "#3f3", "#33f", "#f66", "#6f6", "#66f"];
var targetStructArray = [];
function HandleTargetData(data) {
//Go through all our existing targets and mark them as not updated
for (var i = 0; i < targetStructArray.length; i++) {
targetStructArray[i].updated = false;
}
for (var i = 0; i < data.targets.length; i++) {
var targetData = data.targets[i];
var targetStruct = undefined;
//find our targetStruct
for (var j = 0; j < targetStructArray.length; j++) {
if (targetStructArray[j].id == targetData.id) {
targetStruct = targetStructArray[j];
break;
}
}
//If it doesnt exist, create it
if (!targetStruct) {
var path = paper.path();
path.attr({ "stroke-width": "2", "stroke": "#888" });
path.addPart(['M', targetData.x, targetData.y]);
var circle = paper.circle(targetData.x, targetData.y, 15, 15).attr({
stroke: "none",
fill: arrayColours[Math.floor(Math.random() * arrayColours.length)] //random colour
});
//Create our struct
targetStruct = {
circle: circle,
path: path,
id: targetData.id,
updated: false
};
targetStructArray.push(targetStruct);
}
else {
targetStruct.circle.attr({ cx: targetData.x, cy: targetData.y });
targetStruct.path.addPart(['L', targetData.x, targetData.y]);
}
//ensure we are set as updated
targetStruct.updated = true;
}
//Go through all our existing targets and delete any that werent updated
for (var i = targetStructArray.length - 1; i >= 0; i--) {
if (!targetStructArray[i].updated) {
targetStructArray[i].circle.remove();
targetStructArray[i].path.remove();
targetStructArray[i].circle.removeData();
targetStructArray[i].path.removeData();
targetStructArray[i].circle = null;
targetStructArray[i].path = null;
targetStructArray[i] = null;
targetStructArray.remove(i);
}
}
}
I use two functions not listed here which are John Resig's Array.Remove and a Raphael helper function from a different question

Categories

Resources