I am trying to clone several svgs from the same data, but when I apply a colour to one of them it also applies to the others as well. I'm not sure I am cloning the svg correctly. Here is my code:
var canvas = new fabric.Canvas('canvas');
var svgObject = null;
fabric.loadSVGFromURL("http://fabricjs.com/assets/131.svg", function(objects, options) {
svgObject = fabric.util.groupSVGElements(objects, options);
var object1 = fabric.util.object.clone(svgObject);
colourSVG(object1, "rgb(0,0,0)", "rgba(151,0,0,1)");
canvas.add(object1);
var object2 = fabric.util.object.clone(svgObject);
object2.top = 200;
canvas.add(object2).renderAll();
});
function colourSVG(_obj, _keyColourString, _fillColourString){
if (!_obj.paths) {
_obj.setFill(_fillColourString);
}
else if (_obj.paths) {
for (var i = 0; i < _obj.paths.length; i++) {
if(_obj.paths[i].fill === _keyColourString){
_obj.paths[i].setFill(_fillColourString);
console.log("colour found");
}
else{
console.log(_obj.paths[i].fill);
}
}
}
}
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<canvas id="canvas" width="800" height="500" ></canvas>
I think you were just cloning the objects incorrectly.
var canvas = new fabric.Canvas('canvas');
var svgObject = null;
fabric.loadSVGFromURL("http://fabricjs.com/assets/131.svg", function(objects, options) {
svgObject = fabric.util.groupSVGElements(objects, options);
svgObject.clone(function(o) {
colourSVG(o, "rgb(0,0,0)", "rgba(151,0,0,1)");
canvas.add(o);
});
svgObject.clone(function(o) {
o.top = 200;
canvas.add(o);
});
canvas.renderAll();
});
function colourSVG(_obj, _keyColourString, _fillColourString) {
if (!_obj.paths) {
_obj.setFill(_fillColourString);
} else if (_obj.paths) {
for (var i = 0; i < _obj.paths.length; i++) {
if (_obj.paths[i].fill === _keyColourString) {
_obj.paths[i].setFill(_fillColourString);
console.log("colour found");
} else {
console.log(_obj);
console.log(_obj.paths[i].fill);
}
}
}
}
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<canvas id="canvas" width="800" height="500"></canvas>
Related
I have very simple slot casino game with five rolls and three rows.
I am stuck with a problem that I have not been able to solve for several hours. It's about the roll animation. I have the following assumption:
The roll has at least 10 symbols, only 3 are displayed on the screen (the rest is above the screen - invisible)
When you click on the space, the drawing starts (I managed to do it)
If the last symbol is just above the roller, the position is reset and so on and on - I did the spinning effect of the roller. Let's say it works
The problem that I encountered is that I don't know how to stop the reel after e.g. 3 seconds.
As you can see I tried to use Reel.stop () but it doesn't work.
By the way - is this code correct? Can something be improved in it?
#edit 1
i change method move_reel, but
#edit 2
adding setTimeout to Reel:stop method
/*var FPS = 60;
setInterval(function() {
render();
}, 1000/FPS);
*/
var tile_1 = new Image();
var tile_1_loaded = false;
tile_1.src = "https://i.ibb.co/tsC6G4R/tile-1.png";
var tile_2 = new Image();
var tile_2_loaded = false;
tile_2.src = "https://i.ibb.co/Ns1ZKg2/tile-2.png";
// GAME SETTINGS
var reels = [];
// REEL
function Reel(x, y, tiles) {
this.x = x;
this.y = y;
this.tiles = tiles;
var start = 0;
this.draw = function(){
for(var i = 0; i < this.tiles.length; i++) {
if (this.tiles[i] == 1) {
tile_name = tile_1;
}
else {
tile_name = tile_2;
}
y_offset = this.y + 100 * i + 19;
ctx.drawImage(tile_name, x, y_offset, 100, 100);
}
}
this.update = function(){
if (this.y < 0) {
this.y += 15;
}
else {
this.y = -715;
}
}
this.stop = function(){
setTimeout(() => {
this.y = y;
}, 2000);
}
}
function drawReels() {
ctx.beginPath();
ctx.rect(0, 0, canvas.width, 300);
ctx.clip();
reels.push(new Reel(0, -715, [1,2,2,1,1,2,2,2,1,2,1,1,2,2,1]));
reels.push(new Reel(100, -715, [1,2,1,2,1,2,1,2,1,2,2,1,2,1,1]));
reels.push(new Reel(200, -715, [2,2,1,1,1,1,1,1,2,2,2,1,1,2,1]));
reels.push(new Reel(300, -715, [1,2,1,2,1,2,1,2,1,2,2,1,2,1,1]));
reels.push(new Reel(400, -715, [1,2,1,2,1,2,1,2,1,2,2,1,2,1,1]));
for(var i = 0; i < reels.length; i++) {
reels[i].draw();
}
}
function spin() {
let animate_reel;
animate_reel = requestAnimationFrame(spin);
for(i = 0; i < reels.length; i++) {
move_reel(i);
}
}
var move_reel = function(index) {
reels[index].update();
reels[index].draw();
reels[index].stop();
}
function handleKey(evt) {
if (evt.keyCode == 32) {
spin();
}
}
function init() {
canvas = document.getElementById("slots");
ctx = canvas.getContext("2d");;
window.addEventListener('keydown', handleKey, true);
tile_1.onload = function() {
tile_1_loaded = true;
if (tile_1_loaded && tile_2_loaded) drawReels();
};
tile_2.onload = function() {
tile_2_loaded = true;
if (tile_1_loaded && tile_2_loaded) drawReels();
};
}
init()
* {
margin: 0;
padding: 0;
}
body {
background: #0d012c;
color: #fff;
text-transform: uppercase;
overflow: hidden;
}
canvas {
display: block;
margin: 0;
padding: 0;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Slots</title>
</head>
<body>
<div id="game">
<canvas id="slots" width="1500" height="640"></canvas>
</div>
</body>
</html>
I suggest you use the global setTimeout() method. It sets a timer which executes a function or specified piece of code once the timer expires.
setTimeout(() => {
console.log("This message was Delayed for 3 seconds.");
}, 3000)
I want to fill a text with particles like this
I tried to do this using p5.js but I am stuck where the particles are only appearing on the edges. Any idea to accomplish this rather than having it on the edges?
Here is my attempt.
Thanks a ton in advance :)
SteeringDemo.html
<body>
<script>
var font;
var vehicles=[];
var x=1360;
var y=400;
function preload() {
font=loadFont('Poppins-Medium.ttf')
}
function setup() {
var canvasDiv = document.getElementById('canvas');
var width = canvasDiv.offsetWidth;
var sketchCanvas = createCanvas(width,450);
console.log(sketchCanvas);
sketchCanvas.parent("canvas");
background('#fff');
var points=font.textToPoints('B',x/3,y/2,240);
console.log(points);
for(i=0;i<points.length;i++){
var pt=points[i];
var vehicle = new Vehicle(pt.x, pt.y);
vehicles.push(vehicle);
}
}
function draw() {
background('#fff');
for(var i=0; i< vehicles.length;i++){
var v=vehicles[i];
v.behaviors();
v.update();
v.show();
}
}
</script>
<div class="container">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div id="canvas"></div>
</div>
</div>
</div>
</body>
Vehicle.js
function Vehicle(x,y) {
this.pos= createVector(random(width),random(height));
this.target=createVector(x,y);
this.vel= p5.Vector.random2D();
this.acc= createVector();
this.radius=8;
this.maxspeed=10;
this.maxForce=1;
}
Vehicle.prototype.behaviors=function () {
var arrive=this.arrive(this.target);
var mouse= createVector(mouseX,mouseY);
var flee=this.flee(mouse);
arrive.mult(1);
flee.mult(5);
this.applyForce(arrive);
this.applyForce(flee);
}
Vehicle.prototype.applyForce =function (f) {
this.acc.add(f);
}
Vehicle.prototype.update=function () {
this.pos.add(this.vel);
this.vel.add(this.acc);
this.acc.mult(0);
}
Vehicle.prototype.show=function () {
stroke('#0097a7');
strokeWeight(4);
point(this.pos.x,this.pos.y);
}
Vehicle.prototype.arrive= function (target) {
var desired=p5.Vector.sub(target,this.pos);
var d=desired.mag();
var speed=this.maxspeed;
if(d < 100) {
speed=map(d,0,100,0,this.maxspeed)
}
desired.setMag(speed);
var steer=p5.Vector.sub(desired,this.vel);
steer.limit(this.maxForce);
return steer;
}
Vehicle.prototype.flee= function (target) {
var desired=p5.Vector.sub(target,this.pos);
var d= desired.mag();
if(d <50) {
desired.setMag(this.maxspeed);
desired.mult(-1);
var steer=p5.Vector.sub(desired,this.vel);
steer.limit(this.maxForce);
return steer;
} else {
return createVector(0,0);
}
}
Though you could but, you don't have to use p5*js to achieve that animation. Fortunately, I've came across a javascript library called Particle Slider
and as it turns out, yalantis also using the same library for their animation.
Here is how you could accomplish such animation using that library.
let init = () => {
PS.renderText({
text: 'B',
fontFamily: 'Arial',
fontSize: 200,
fontColor: '#00E2FA',
fontWeight: 'bold'
});
var myPS = new ParticleSlider({
ptlGap: 3,
ptlSize: 1,
mouseForce: 70
});
window.onresize = () => {
myPS.width = window.innerWidth;
myPS.height = window.innerHeight;
}
}
window.onload = init;
html, body {
width: 100%;
height: 100%;
overflow: hidden;
background-color: black;
}
<script src="https://istack.000webhostapp.com/PS.js"></script>
<!-- DO NOT CHANGE ANYTHING AFTER THIS LINE -->
<div class="slides">
<div class="slide"> </div>
</div>
<canvas class="draw"></canvas>
<!-- DO NOT CHANGE ANYTHING BEFORE THIS LINE -->
Yes! It's really that easy :)
also, checkout a demo on jsFiddle
for future reference always refer to the official documentation
I want to take an image from user, display it and allow user to adjust it within the div and then capture the adjusted image and append it to the body.
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="html2canvas.js"></script>
<script src="Canvas2Image.js"></script>
<script src="e-smart-zoom-jquery.min.js"></script>
<style type="text/css">
#wrapper {
width: 980px;
height: 500px;
}
</style>
</head>
<body>
<div id="wrapper" style="background-color: white" width="980px" height="500px">
<img id="imageFullScreen" src="https://s-media-cache-ak0.pinimg.com/736x/b5/41/8d/b5418dcc2ab6efa7fe51d8bffd385343.jpg">
</div>
<br/>
<input type="button" id="btnSave" value="Save PNG"/>
<input type="file" accept="image/*" name="photo" id="imgInp" onchange="loadFile(event);"/>
<div id="img-out"></div>
<script type="text/javascript">
$(document).ready(function() {
$('#imageFullScreen').smartZoom({'containerClass':'zoomableContainer'});
function moveButtonClickHandler(e){
var pixelsToMoveOnX = 0;
var pixelsToMoveOnY = 0;
switch(e.target.id){
case "leftPositionMap":
pixelsToMoveOnX = 50;
break;
case "rightPositionMap":
pixelsToMoveOnX = -50;
break;
case "topPositionMap":
pixelsToMoveOnY = 50;
break;
case "bottomPositionMap":
pixelsToMoveOnY = -50;
break;
}
$('#imageFullScreen').smartZoom('pan', pixelsToMoveOnX, pixelsToMoveOnY);
}
});
$(function() {
$("#btnSave").click(function() {
html2canvas($("#wrapper"), {
onrendered: function(canvas) {
var img = canvas.toDataURL("image/png");
$('body').append('<img src="'+img+'"/>');
}
});
});
});
var loadFile = function(event) {
oldimg = $('.imageFullScreen').attr('src');
var preview = document.getElementById('imageFullScreen');
preview.src = URL.createObjectURL(event.target.files[0]);
newimg = preview.src;
if(newimg.indexOf('/null') > -1) {
preview.src = oldimg;
$('#imageFullScreen').smartZoom({'containerClass':'zoomableContainer'});
}
};
</script>
</body>
</html>
I am able to display the image with the src attribute, and zoom and drag it but unable to take image from the user.
jsfiddle
Try using FileReader instead.
var reader = new FileReader();
$(document).ready(function() {
reader.addEventListener("load", function() {
var preview = document.getElementById('imageFullScreen');
$('#imageFullScreen').smartZoom("destroy");
preview.src = reader.result;
$('#imageFullScreen').smartZoom();
}, false);
$("#imgInp").on("change", function(event) {
if (event.target.files[0]) {
reader.readAsDataURL(event.target.files[0]);
}
});
function moveButtonClickHandler(e) {
var pixelsToMoveOnX = 0;
var pixelsToMoveOnY = 0;
switch (e.target.id) {
case "leftPositionMap":
pixelsToMoveOnX = 50;
break;
case "rightPositionMap":
pixelsToMoveOnX = -50;
break;
case "topPositionMap":
pixelsToMoveOnY = 50;
break;
case "bottomPositionMap":
pixelsToMoveOnY = -50;
break;
}
$('#imageFullScreen').smartZoom('pan', pixelsToMoveOnX, pixelsToMoveOnY);
}
});
$('#imageFullScreen').smartZoom();
$(function() {
$("#btnSave").click(function() {
html2canvas($("#wrapper"), {
onrendered: function(canvas) {
var img = canvas.toDataURL("image/png");
$('body').append('<img src="' + img + '"/>');
}
});
});
});
Here is the JS Fiddle
EDIT : You have to destroy the smartZoom object before changing the src and then have to reinitialize it.
I am working on fabric js application & I need to increase/decrease the font size when we resize the font with mouse
my tried code
var canvas = new fabric.Canvas('canvas');
$(document).ready(function() {
$('#text-font-size').keyup(function() {
var val = $(this).val();
if (isNaN(val)) {
alert('please enter number');
$(this).val('');
}
var activeObject = canvas.getActiveObject();
activeObject.fontSize = val;
canvas.renderAll();
});
$('#add-text-btn').click(function() {
if ($('#text-font-size').val()) {
var txtfontsize = $('#text-font-size').val();
} else {
var txtfontsize = 40;
}
var message = $('#add-text-value').val();
//var txtfontfamily = $('#font-family').val();
var new_text = new fabric.IText(message, {
left: 100,
top: 100,
fontSize: txtfontsize,
//fontFamily: txtfontfamily,
fill: '#000'
});
canvas.add(new_text);
canvas.setActiveObject(new_text);
});
canvas.on('object:selected', function(options) {
if (options.target) {
$("textarea#add-text-value").val(options.target.text);
$("#text-font-size").val(options.target.fontSize);
}
});
canvas.on('object:scaling', function(options) {
if (options.target) {
$("textarea#add-text-value").val(options.target.text);
$("#text-font-size").val(options.target.fontSize);
}
});
canvas.on('object:modified', function(options) {
if (options.target) {
$("textarea#add-text-value").val(options.target.text);
$("#text-font-size").val(options.target.fontSize);
}
});
});
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add-text-btn">Add text</button><br><br>
<textarea rows="7" id="add-text-value">Your Text Here</textarea>
<br>
<input id="text-font-size" type="text" class="form-control">
<canvas id='canvas' width="500" height="400" style="border:#000 1px solid;"></canvas>
but this this just rescale the text not increase/decrease the font size but i have to resize the font size like in this
The idea is using the canvas.on("object:modified") event to reset the scaling to 1 and increase fontSize to fit the new size.
fabric.Object.lockUniScaling is a suggested addition.
var canvas = new fabric.Canvas('canvas');
$(document).ready(function() {
$('#text-font-size').keyup(function() {
var val = $(this).val();
if (isNaN(val)) {
alert('please enter number');
$(this).val('');
}
var activeObject = canvas.getActiveObject();
activeObject.fontSize = val;
canvas.renderAll();
});
$('#add-text-btn').click(function() {
if ($('#text-font-size').val()) {
var txtfontsize = $('#text-font-size').val();
} else {
var txtfontsize = 40;
}
var message = $('#add-text-value').val();
//var txtfontfamily = $('#font-family').val();
var new_text = new fabric.IText(message, {
left: 100,
top: 100,
fontSize: txtfontsize,
lockUniScaling: true,
//fontFamily: txtfontfamily,
fill: '#000'
});
canvas.add(new_text);
canvas.setActiveObject(new_text);
});
canvas.on('object:selected', function(options) {
if (options.target) {
$("textarea#add-text-value").val(options.target.text);
$("#text-font-size").val(options.target.fontSize);
}
});
canvas.on('object:scaling', function(event) {
if (event.target) {
$("textarea#add-text-value").val(event.target.text);
$("#text-font-size").val((event.target.fontSize * event.target.scaleX).toFixed(0));
}
});
canvas.on('object:modified', function(event) {
if (event.target) {
event.target.fontSize *= event.target.scaleX;
event.target.fontSize = event.target.fontSize.toFixed(0);
event.target.scaleX = 1;
event.target.scaleY = 1;
event.target._clearCache();
$("textarea#add-text-value").val(event.target.text);
$("#text-font-size").val(event.target.fontSize);
}
});
});
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add-text-btn">Add text</button>
<br>
<br>
<textarea rows="7" id="add-text-value">Your Text Here</textarea>
<br>
<input id="text-font-size" placeholder="fontsize" type="number" class="form-control">
<canvas id='canvas' width="500" height="400" style="border:#000 1px solid;"></canvas>
While perhaps not the best approach (I'm new to Fabric), this is working for me with version 4.3.0:
canvas.on('text:changed', function (e) {
console.log('Text:', e.target.text, e.target.text.length)
let objectSelection = canvas.getActiveObject()
switch (e.target.text.length) {
case 10:
console.log(`Text is ${e.target.text.length} characters in length.`)
objectSelection.set('fontSize', 100)
break
case 15:
console.log(`Text is ${e.target.text.length} characters in length.`)
objectSelection.set('fontSize', 85)
break
case 25:
console.log(`Text is ${e.target.text.length} characters in length.`)
objectSelection.set('fontSize', 60)
break
}
})
canvas.on('text:editing:exited', function (e) {
console.log('Text edited!')
})
I took inspiration from another answer, which does the job.
As i was going through canvas tutorial, i am getting error:" Point is not defined" and My actual output differs from expected output.Iam not able to drag the circle with mouse.
ReferenceError: Point is not defined in logic.js
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Drawing Circles in Canvas</title>
<link rel="stylesheet" href="css/style.css"/>
</head>
<body width="100%" height="100%">
<header>
<h1>Drawing in Canvas</h1>
</header>
<canvas id="game" width="768" height="400">
Sorry, your web browser does not support
Canvas content.
</canvas>
<script src="js/jquery-1.10.2.min.js">
</script>
<script src="js/logic.js"></script>
</body>
</html>
logic.js
var untangleGame={
circle: [],
thinLineThickness: 1,
lines: []
};
function Circle(x,y,radius){
this.x=x;
this.y=y;
this.radius=radius;
}
function Line(startPoint,endPoint,thickness){
this.startPoint=startPoint;
this.endPoint=endPoint;
this.thickness=thickness;
}
function drawcircle(ctx,x,y,radius){
ctx.fillStyle="rgba(200,200,100,.9)";
ctx.beginPath();
ctx.arc(x,y,radius,0,Math.PI*2,true);
ctx.closePath();
ctx.fill();
}
function connectCircles(){
for(var i=0;i<untangleGame.circle.length;i++){
var startPoint=untangleGame.circle[i];
for(var j=0;j<i;j++){
var endPoint=untangleGame.circle[j];
untangleGame.lines.push(new
Line(startPoint,endPoint,untangleGame.thinLineThickness));
}
}
}
function drawLine(ctx,x1,y1,x2,y2,thickness){
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.lineWidth=thickness;
ctx.strokeStyle="#cfc";
ctx.stroke();
}
function clear(ctx){
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
}
$(function(){
var canvas=document.getElementById('game');
var ctx=canvas.getContext('2d');
var circleRadius=10;
var width=canvas.width;
var height=canvas.height;
var circlesCount=5;
for(var i=0;i<circlesCount;i++){
var x=Math.random()*width;
var y=Math.random()*height;
drawcircle(ctx,x,y,circleRadius);
untangleGame.circle.push(new Circle(x,y,circleRadius));
}
connectCircles();
$("#game").mousedown(function(e){
var canvasPosition=$(this).offset();
var mouseX=e.layerX || 0;
var mouseY=e.layerY || 0;
for(var i=0;i<untangleGame.circle.length;i++){
var circleX=untangleGame.circle[i].x;
var circleY=untangleGame.circle[i].y;
var radius=untangleGame.circle[i].radius;
if(Math.pow(mouseX-circleX,2)+Math.pow(mouseY-circleY,2)
<Math.pow(radius,2)){
untangleGame.targetCircle=i;
break;
}
}
});
$("#game").mousemove(function(e){
if(untangleGame.targetCircle != undefined){
var canvasPosition=$(this).offset();
var mouseX=e.layerX || 0;
var mouseY=e.layerY || 0;
var
radius=untangleGame.circle[untangleGame.targetCircle].radius;
untangleGame.circle[untangleGame.targetCircle]=new
Circle(mouseX,mouseY,radius);
}
connectCircles();
});
$("#game").mouseup(function(e){
untangleGame.targetCircle=undefined;
});
setInterval(gameloop,30);
});
function gameloop(){
var canvas=document.getElementById('game');
var ctx=canvas.getContext('2d');
clear(ctx);
for(var i=0;i<untangleGame.lines.length;i++){
var line=untangleGame.lines[i];
var startPoint=line.startPoint;
var endPoint=line.endPoint;
var thickness=line.thickness;
drawLine(ctx,startPoint.x,startPoint.y,endPoint.x,endPoint.y,thickness);
}
for(var i=0;i<untangleGame.circle.length;i++){
var circle=untangleGame.circle[i];
drawcircle(ctx,point.x,point.y,circle.radius);
}
}
style.css
canvas{
background: #333;
}
Output Expected:
Output expected of Image link O/p Expected link
Looks like you are using point instead of circle in the for loop in gameloop
for (var i = 0; i < untangleGame.circle.length; i++) {
var circle = untangleGame.circle[i];
drawcircle(ctx, circle.x, circle.y, circle.radius);
}
Demo: Fiddle