How can I change individual object's attributes in the Raphael SET? - javascript

Let's consider I have a circle and a rectangle in ss Raphael Set:
<script type="text/javascript">
var paper = Raphael("canvas", 500, 500),
r = paper.rect(100, 100, 140, 80),
c = paper.circle(100, 100, 80);
c.attr({fill: 'red', stroke: 'black'});
r.attr({fill: 'black', stroke: 'red'});
var ss = paper.set(r, c);
</script>
Now at some point in the program, I need to change say Circle's fill: 'white'.
I know that it is possible to change Set's attribute as follows: ss.attr({fill: 'white'}), but this applies to all of its elements. I still want to keep the color of rectangle unchanged. I have tried ss.c.attr(), but no result.
Any idea how can I achieve this. Thanks

I had the same problem a while ago. Then I found out that you can access SET individual objects just like in array.
For exp.; ss[0] returns your r rectangle object; i.e. ss[0].attr({'//here'})

Related

Set position for object while adding it to canvas in Fabric.js

I am adding an object to my fabric.js canvas using JavaScript (in a React.JS project), but I don't want it to be rendered in the top left corner every time. I want it so that when I use the canvas.add() function, I can specify the x, y co-ordinates at which I can render the object.
Something like this maybe -
const addObject = (canvas) => {
img = fabric.Image(img);
canvas.add(img, 20, 15) //(20,15) represent the x,y co-ordinates of where I want to render img
I just want it so that my object is added to the specified position automatically on calling the addObject() function.
You can try using the LEFT and TOP.
For example, locating can be done this way. This could be an example for you.
var circle = new fabric.Circle({
left: 20,
top: 15,
radius: 25,
fill: randomColor(),
hasRotatingPoint: true
});
canvas.add(circle)
If you want it to be random, you can use it as follows.
var circle = new fabric.Circle({
left: fabric.util.getRandomInt(25, canvas.width - 25),
top: fabric.util.getRandomInt(25, canvas.height - 25),
radius: 25,
fill: randomColor(),
hasRotatingPoint: true
});
canvas.add(circle);
Hopefully it benefits your business.

Adding Width to a Curved Path in Three.js

I created a racetrack shaped curve in three.js with the following code:
var path = new THREE.Path();
path.moveTo(150,50);
path.lineTo(150,150);
path.quadraticCurveTo(150,175,100,175);
path.quadraticCurveTo(50,175,50,150);
path.lineTo(50,50);
path.quadraticCurveTo(50,25,100,25);
path.quadraticCurveTo(150,25,150,50);
var pathPoints = path.getPoints();
var pathGeometry = new THREE.BufferGeometry().setFromPoints(pathPoints);
var pathMaterial = new THREE.LineBasicMaterial({color:0xFF1493});
var raceTrack = new THREE.Line(pathGeometry,pathMaterial);
scene.add(raceTrack);
}
Right now, the track is just a single line, and I wanted to know if it was possible to make the track into a geometry with a width (still 2D) so that I can add a texture to it.
Currently, the path looks something like this:
What I'd like is to be able to draw the same shape, but just increase the width of the line:
With R91, three.js added support for triangulated lines. This approach enables line width greater than 1px in a reliable way.
Demo: https://threejs.org/examples/webgl_lines_fat.html
There are no textures applied on the example but uv-coordinates are generated for the underlying geometry.
With regular Line-objects, there is no way to achieve this.
Here are a few options you can try:
create your complete "race-track" as a geometry, including both the inner and the outer line. I have no idea what you need this for, but this is probably the most "correct" way to do something like this (using this approach, the race-track can have different width at different points, you have control over how bends and turns behave and so on). A quick example:
const shape = new THREE.Shape();
shape.moveTo(150, 50);
shape.lineTo(150, 150);
shape.quadraticCurveTo(150, 175, 100, 175);
shape.quadraticCurveTo(50, 175, 50, 150);
shape.lineTo(50, 50);
shape.quadraticCurveTo(50, 25, 100, 25);
shape.quadraticCurveTo(150, 25, 150, 50);
const innerShape = new THREE.Path();
innerShape.moveTo(140, 40);
innerShape.lineTo(140, 140);
innerShape.quadraticCurveTo(140, 165, 90, 165);
innerShape.quadraticCurveTo(60, 165, 60, 140);
innerShape.lineTo(60, 50);
innerShape.quadraticCurveTo(60, 35, 110, 35);
innerShape.quadraticCurveTo(140, 35, 140, 60);
shape.holes.push(innerShape);
var raceTrack = new THREE.Mesh(
new THREE.ShapeGeometry(shape),
new THREE.MeshBasicMaterial({ color: 0xff1493 })
);
full code here: https://codepen.io/usefulthink/pen/eMBgmE
alternatively, you can use the new fat-lines implementation shown here: https://threejs.org/examples/?q=line#webgl_lines_fat or the MeshLine implementation from here: https://github.com/spite/THREE.MeshLine, but I have the feeling those do not what you are looking for...

Extending the default OpenLayers edit style?

I have a vector style, with a larger image: radius. I would like to have the select interaction's style match the vector style's image: radius.
How can I do so without manually redefining the whole editing style based on this page in the documentation?
Is it possible to take the default style and override only one part? Like the image's radius? Or at least redefine only the whole image?
Fiddle.
Share a style function between ol.layer.Vector and ol.interaction.Select and when selecting, change a variable that will be read within your function:
var radius = 10;
var styleFunction = function() {
return [
new ol.style.Style({
image: new ol.style.Circle({
radius: radius,
fill: new ol.style.Fill({
color: 'green'
})
})
})
];
};
var select_interaction = new ol.interaction.Select({
style: styleFunction
});
select_interaction.on('select', function(evt) {
radius = evt.selected.length > 0 ? 20 : 10;
});
I'm proposing a ol.style.Circle#setRadius that could be used in this case.

Positioning A Set in Raphael Paper

Is there any way to group bunch of elements of paper in one set and only position that set in the paper?
For example At This Example I was trying to put some circles in side a rectangle and just position the rectangle in each part of the paper. Can you please let me know how to do it?
var paper = Raphael('my-canvas', 500, 300);
paper.canvas.style.backgroundColor = '#F00';
var rect = paper.rect(5, 5, 100, 100);
var st = paper.set();
st.push(
rect.circle(10, 10, 5),
rect.circle(30, 10, 5));
You can do this via a transform on the set (you could also do it with another attribute like x,y but only if the elements use that specific attribute).
Its worth noting, that although you can apply a transform to the set, it is in effect applying the transform to each element in the set. Ie there is no specific 'set' or 'group' element in Raphael (there is in Snap.svg which is its updated brother, but doesn't quite have the same backwards compatibility). So there is no true hierarchy of groups, where they could have separate transforms which cascade down.
var paper = Raphael('my-canvas', 500, 300);
paper.canvas.style.backgroundColor = '#F00';
var rect = paper.rect(5, 5, 100, 100);
var st = paper.set();
st.push(
paper.rect(5, 5, 100, 100),
paper.circle(10, 10, 5).attr({ fill: 'blue' }),
paper.circle(30, 10, 5).attr({ fill: 'green' })
);
st.transform('t20,20');
st.animate({ transform: 't100,100' }, 2000);
Its worth looking at the Raphael docs for transforms if not sure here
jsfiddle
Instead of using a set, you can create a new div, add a new paper element to this div and then change the position of the div.
If you are using jquery, it could look something like this:
$(".body").append('<div id="setContainer"></div>');
paper = new Raphael(document.getElementById("setContainer"), 500, 300);
paper.canvas.style.backgroundColor = '#F00';
var rect = paper.rect(5, 5, 100, 100);
var circle = paper.circle(10, 10, 5);
var circle2 = paper.circle(30, 10, 5);
// then you can adjust the position of the div, for example to 100,100
$("#setContainer").css("top", 100);
$("#setContainer").css("left", 100);
The advantage of using this approach rather than a set is that it gives you more flexibility for the way you want to manipulate the elements you are grouping together.
You can even wrap a function around this code in order to define the id of the container programatically if you wanted to create several instances of the same group of elements.

Raphael.js newbie question: how to create a rectangular and lines as ONE object?

In raphael, if I want to render the following shape:
I have to do something like:
var paper = Raphael("notepad", 320, 200);
var rect = paper.rect(...);
var line1 = paper.path(...);
var line2 = paper.path(...);
which create three elements: rect, line1, line2.
BUT, I would like to treat the rendered shape as one object in other js code insteand of three. In Raphael, how can I create this shape which returns me just one object not three?
You want to create a set.
Creates array-like object to keep and operate couple of elements at once. Warning: it doesn't create any elements for itself in the page.
var st = paper.set();
st.push(
paper.circle(10, 10, 5),
paper.circle(30, 10, 5)
);
st.attr({fill: "red"});
Your code would look something like this:
var paper = Raphael("notepad", 320, 200),
st = paper.set();
st.push(
paper.rect(...),
paper.path(...),
paper.path(...)
);
// use st elsewhere
Edit
How can I access individual element in the set then?
You can grab references to the objects before you add them to the set:
var paper = Raphael("notepad", 320, 200),
st = paper.set(),
rect1 = paper.rect(...),
path1 = paper.path(...),
path2 = paper.path(...);
st.push(rect1, path1, path2);
I'm not 100% sure, but since the docs say that a set is "array-like," then you should also be able to access elements in the set using array index notation:
var i, elt;
for (i=0; i<st.length; i++)
{
elt = st[i];
// do stuff with elt
}

Categories

Resources