I have a basic program that essentially just displays an imported svg. Is there any way I can change the fill of the svg?
var img;
function preload() {
img = loadImage("assets/svgImage.svg")
}
function setup() {
createCanvas(720, 400);
background(200);
fill(204, 101, 192, 127);
stroke(127, 63, 120);
image(img, 50, 50, 50, 50)
}
I tried something along the lines of:
function setup() {
img.drawingContext.fillStyle = '#475731'
image(img, 50, 50, 50, 50)
}
But that doesn't seem to do anything for me.
http://zenozeng.github.io/p5.js-svg/examples/#manipulating
The example on the "Manipulating existing SVG" page says you need to use the querySVG function to obtain the path/shape components, then you can modify their fill attribute.
This is the example given:
var svg, path;
function preload() {
svg = loadSVG('test.svg');
frameRate(20);
}
function setup() {
createCanvas(600, 200, SVG);
image(svg, 0, 0, 200, 200);
path = querySVG('path')[1];
}
function draw() {
// update line width of 2nd line
path.attribute('stroke-width', frameCount % 20);
if (frameCount === 18) {
noLoop();
save(); // save current SVG graphics
}
}
I imagine in your case it would be:
path.attribute('fill', '#475731');
Related
In the snippet below, I place two red squares next to each other. You can see there is no gap between them.
If I try to do the same thing with moving objects, there is a slight gap. What's the right way to do this?
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>
</head>
<body>
<script>
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
physics: { default: 'arcade' },
scene: { create: create, update: update },
};
var game = new Phaser.Game(config);
var red, red2, yellow, yellow2;
const velocity = -300;
function create() {
red = this.add.rectangle(400, 200, 100, 100, 0xff0000).setOrigin(0, 0);
red2 = this.add.rectangle(red.x + 100, 250, 100, 100, 0xff6666).setOrigin(0, 0);
yellow = this.add.rectangle(400, 400, 100, 100, 0xffff00).setOrigin(0, 0);
this.physics.add.existing(yellow);
yellow.body.velocity.x = velocity;
}
function update() {
if (yellow.x < 200 && !yellow2) {
yellow2 = this.add.rectangle(yellow.x + 100, 450, 100, 100, 0xffff66).setOrigin(0, 0);
this.physics.add.existing(yellow2);
yellow2.body.velocity.x = velocity;
}
if (yellow.x < -200) {
this.scene.restart();
yellow2 = undefined;
}
}
</script>
</body>
</html>
I think the solution is: Use the position of the physics body by changing yellow.x + 100 to yellow.body.x + 100.
(Or maybe yellow.body.position.x + 100? Not sure what the difference is, or if body.x is just an alias for body.position.x.)
Related: https://phaser.discourse.group/t/lag-in-dom-sprite-position-updates/798
A easy way out is to use the Phaser function: Phaser.Display.Align.To.RightCenter and the event: postupdate.
You then just have to calculate the offset between the objects and add pass it into the function. ( documentation to the Align function). this is based on this solution: phaser forum
canvas{
transform: translate(-40%, -40%) scale(.3);
}
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>
</head>
<body style="overflow:hidden">
<script>
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
physics: { default: 'arcade' },
scene: { create: create, update: update },
};
var game = new Phaser.Game(config);
var red, red2, yellow, yellow2;
const velocity = -300;
var yOffSet = 0;
function create() {
red = this.add.rectangle(400, 200, 100, 100, 0xff0000).setOrigin(0, 0);
red2 = this.add.rectangle(red.x + 100, 250, 100, 100, 0xff6666).setOrigin(0, 0);
yellow = this.add.rectangle(400, 400, 100, 100, 0xffff00).setOrigin(0, 0);
this.physics.add.existing(yellow);
yellow.body.velocity.x = velocity;
this.events.on("postupdate", function () {
if (yellow && yellow2) {
Phaser.Display.Align.To.RightCenter(yellow2, yellow, 0, yOffSet);
}
});
}
function update(time, delta) {
if (yellow.x < 200 && !yellow2) {
yellow2 = this.add.rectangle(yellow.x + 100, 450, 100, 100, 0xffff66).setOrigin(0, 0);
this.physics.add.existing(yellow2);
yellow2.body.velocity.x = velocity;
yOffSet = yellow2.y - yellow.y
}
if (yellow.x < -200) {
this.scene.restart();
yellow2 = undefined
}
}
</script>
</body>
</html>
Alternativly you could, calculate the x position more exact, but it is no easy since, the update function is not called in the same time interval. This could cause minor overlap or splitting.
// deltaTime being the the second paramenter of the update function
yellow2 = this.add.rectangle(yellow.x + 100 + (velocity * deltaTime), 450, 100, 100, 0xff0000).setOrigin(0, 0);
Or even easier, you could simply set the x in the postUpdate event (without Align)
this.events.on("postupdate", function () {
if ( yellow2) {
yellow2.x =yellow.x + 100;
}
});
Is there a way to set the width and height of an iText object? When creating the object if you set width and height it doesn't do anything. What I am after is the bounding box to be a fixed size on the canvas as an editable region, I have already extended the iText class to allow for individual character editing but I can't seem to work out how to size the box as a fixed size and allow content editing inside of it. Bare in mind that the text box can't be moved or scaled, it's static.
It's Too late for answer but other may be looking for answer.
First of all You can use TextBox class of fabricjs if you want to give fixed width & height to Text field. It is Subclass of Itext. But the problem with TextBox was it's text wrap.
So If you don't want to use TextBox but still want to have fixed width and height with Itext then following extended subclass can help you.
I have overridden the initDimensions method .
this.LimitedTextbox = fabric.util.createClass(fabric.IText, {
initDimensions: function() {
this.isEditing && this.initDelayedCursor();
this.clearContextTop();
if (this.__skipDimension) {
return;
}
this._splitText();
this._clearCache();
if (this.path) {
this.width = this.path.width;
this.height = this.path.height;
}
else {
let width = this.calcTextWidth();
if(width>this.maxWidth){
this.width = width;
}else{
this.width = this.maxWidth;
}
this.height = this.calcTextHeight();
}
if (this.textAlign.indexOf('justify') !== -1) {
this.enlargeSpaces();
}
this.saveState({ propertySet: '_dimensionAffectingProps' });
},
onKeyDown:function(e){
if (e.keyCode == 13 && this._textLines.length>=this.maxLines) {
this.exitEditing();
}
this.callSuper('onKeyDown',e);
let maxLine = Math.max(...this.__lineWidths);
self.changeBorderWidth(this.toObject().groupId, this, { iWidth:
this.width, iHeight: this.height,maxLine:maxLine,id:this.toObject().id
},false,this.toObject().customType==='stamp_input');
if(this.dynamicMinWidth>this.maxWidth){
this.width = this.dynamicMinWidth;
}
},
});
Then you can use like below
const text = new this.LimitedTextbox(txt, {
left: 100,
top: 100,
fontFamily: "arial",
angle: 0,
fontSize: 24,
fontWeight: "bold",
hasControls: true,
hoverCursor: "text",
width:250,
maxWidth: 250,
maxLines: 3,
hasRotatingPoint: true,
});
I Hope it helps , you can modify initDimensions as per your requirement , you can also see other methods in fabric's documemtation.
I am new to processing, currently I want to display a 3D ball and also add a text label to the 3D ball.
I am using the code as below:
// this function is called when this sketch is first loaded
void setup()
{
// choose size (width, height) of your sketch
size(720, 546, P3D);
// Choose background color for your sketch
background(0);
}
// This function is called repeatedly to draw stuff on screen.
void draw()
{
lights();
pushMatrix();
translate(500, height*0.35, 0);
fill(236,112,20);
noStroke();
sphere(40);
popMatrix();
//fill(255);
fill(255,112,20);
textAlign(CENTER);
textSize(15);
stroke(10);
text("hihihihi", 500, height*0.35);
}
It turned out that the text "hihihihi" is covered by the ball, but when I do it with 2D object it displays good. Is there anything wrong here, can anyone tell me what might be the problem of my code?Thanks!
Notice that your sphere has a radius of 40 which is means a diameter of 80 and you're drawing both the text and sphere at the same horizontal position(500).
Move the text to the right to avoid the sphere occluding it:
void setup()
{
size(720, 546, P3D);
background(0);
}
void draw()
{
lights();
pushMatrix();
translate(500, height*0.35, 0);
fill(236, 112, 20);
noStroke();
sphere(40);
popMatrix();
fill(255, 112, 20);
textAlign(CENTER);
textSize(15);
stroke(10);
text("hihihihi", 585, height*0.35);//make sure the text isn't occluded by anything else(like a sphere)
}
If you want to render text on a sphere I recommend trying PShape and PGraphics.
Here's a minimal example:
PShape sphere;
void setup()
{
size(720, 546, P3D);
background(0);
PGraphics sphereTexture = createGraphics(40,40);
sphereTexture.beginDraw();
sphereTexture.background(236, 112, 20);
sphereTexture.fill(255);
sphereTexture.text("Hi",20,20);
sphereTexture.endDraw();
sphere = createShape(SPHERE, 40);
sphere.disableStyle();
noStroke();
sphere.setTexture(sphereTexture);
}
void draw()
{
lights();
pushMatrix();
translate(500, height*0.35, 0);
fill(236, 112, 20);
noStroke();
shape(sphere,0,0);
popMatrix();
fill(255, 112, 20);
textAlign(CENTER);
textSize(15);
stroke(10);
text("hihihihi", 585, height*0.35);//make sure the text isn't occluded by anything else(like a sphere)
}
In fabricjs, I want to create a scene in which the object under the mouse rises to the top of the scene in z-index, then once the mouse leaves that object, it goes back to the z-index where it came from. One cannot set object.zindex (which would be nice). Instead, I'm using a placeholder object which is put into the object list at the old position, and then the old object is put back in the position where it was in the list using canvas.insertAt. However this is not working.
See http://jsfiddle.net/rFSEV/ for the status of this.
var canvasS = new fabric.Canvas('canvasS', { renderOnAddition: false, hoverCursor: 'pointer', selection: false });
var bars = {}; //storage for bars (bar number indexed by group object)
var selectedBar = null; //selected bar (group object)
var placeholder = new fabric.Text("XXXXX", { fontSize: 12 });
//pass null or a bar
function selectBar(bar) {
if (selectedBar) {
//remove the old topmost bar and put it back in the right zindex
//PROBLEM: It doesn't go back; it stays at the same zindex
selectedBar.remove();
canvasS.insertAt(selectedBar, selectedBar.XZIndex, true);
selectedBar = null;
}
if (bar) {
//put a placeholder object ("XXX" for now) in the position
//where the bar was, and put the bar in the top position
//so it shows topmost
selectedBar = bar;
canvasS.insertAt(placeholder, selectedBar.XZIndex, true);
canvasS.add(bar);
canvasS.renderAll();
}
}
canvasS.on({
'mouse:move': function(e) {
//hook up dynamic zorder
if (!e.target) return;
if (bars[e.target])
selectBar(e.target);
else
selectBar(null);
},
});
var objcount = canvasS.getObjects().length;
//create bars
for (var i = 0; i < 20; ++i) {
var rect = new fabric.Rect({
left: 0,
top: 0,
rx: 3,
ry: 3,
stroke: 'red',
width: 200,
height: 25
});
rect.setGradientFill({
x1: 0,
y1: 0,
x2: 0,
y2: rect.height,
colorStops: {
0: '#080',
1: '#fff'
}
});
var text = new fabric.Text("Bar number " + (i+1), {
fontSize: 12
});
var group = new fabric.Group([ rect, text ], {
left: i + 101,
top: i * 4 + 26
});
group.hasControls = group.hasBorders = false;
//our properties (not part of fabric)
group.XBar = rect;
group.XZIndex = objcount++;
canvasS.add(group);
bars[group] = i;
}
canvasS.renderAll();
Since fabric.js version 1.1.4 a new method for zIndex manipulation is available:
canvas.moveTo(object, index);
object.moveTo(index);
I think this is helpful for your use case. I've updated your jsfiddle - i hope this is what you want:
jsfiddle
Also make sure you change z-index AFTER adding object to canvas.
So code will looks like:
canvas.add(object);
canvas.moveTo(object, index);
Otherwise fabricjs don`t care about z-indexes you setup.
After I added a line object, I was make the line appear under the object using:
canvas.add(line);
canvas.sendToBack(line);
Other options are
canvas.sendBackwards
canvas.sendToBack
canvas.bringForward
canvas.bringToFront
see: https://github.com/fabricjs/fabric.js/issues/135
You can modify your _chooseObjectsToRender method to have the following change at the end of it, and you'll be able to achieve css-style zIndexing.
objsToRender = objsToRender.sort(function(a, b) {
var sortValue = 0, az = a.zIndex || 0, bz = b.zIndex || 0;
if (az < bz) {
sortValue = -1;
}
else if (az > bz) {
sortValue = 1;
}
return sortValue;
});
https://github.com/fabricjs/fabric.js/pull/5088/files
You can use these two functions to get z-index of a fabric object and modify an object's z-index, since there is not specific method to modify z-index by object index :
fabric.Object.prototype.getZIndex = function() {
return this.canvas.getObjects().indexOf(this);
}
fabric.Canvas.prototype.moveToLayer = function(object,position) {
while(object.getZIndex() > position) {
this.sendBackwards(object);
}
}
I'm having an SVG with 2 layers (back, front).
I need to fill the back with a color (the color will be random).
But the front must stay as it is.
How can I fill the back without affecting the front?
PShape elem;
PShape back;
PShape front;
void setup()
{
size(900,600);
background(255);
fill(100);
elem = loadShape("resources/images/elem.svg");
back = elem.getChild("back");
front = elem.getChild("front");
smooth();
noLoop();
}
void draw(){
elem.disableStyle();
fill(0, 51, 102);
noStroke();
shape(back, 50, 50, 250, 250);
shape(front, 50, 50, 250, 250);
}
Thank you for your help.
Hard to test for your exact setup without the svg.
Still, you should be able to isolate drawing styles for parts of your shapes using pushStyle(),popStyle() pairs.
e.g.
PShape elem;
PShape back;
PShape front;
void setup()
{
size(900,600);
background(255);
fill(100);
elem = loadShape("resources/images/elem.svg");
back = elem.getChild("back");
front = elem.getChild("front");
smooth();
noLoop();
}
void draw(){
elem.disableStyle();
pushStyle();
fill(0, 51, 102);
noStroke();
shape(back, 50, 50, 250, 250);
popStyle();
pushStyle();
shape(front, 50, 50, 250, 250);
popStyle();
}
Indenting is just a visual cue, not actually needed.