I'm using fabricjs to add an animated sprite to my canvas. Unlike in the demo on the fabricjs website I am using an .svg sprite not .png, so it should scale without quality loss.
However when I try and scale up the svg sprite the quality loss is huge. I have tested the sprite as a static object and it scales without any issues with the quality.
Video: https://streamable.com/ya5a
Here's an example, the top image is the sprite with it's default size and below that I have increased it's size and you can see the edges are nasty.
What could be causing the svg to have quality issues when scaling as an animated sprite?
Here is the sprite (crude test image) http://imgh.us/sprite1_2.svg
HTML/JS
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="http://fabricjs.com/lib/fabric.js"></script>
<script src="http://fabricjs.com/js/sprite.class.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
</head>
<body>
<canvas id="canvas" width="500" height="300" style="border:1px solid #444;"></canvas>
<div id="add">Click here to add Animated SVG sprite</div>
<script>
var canvas = this.__canvas = new fabric.Canvas('canvas');
var src1 = "img/sprite1_2.svg";
$("#add").click(function(){
fabric.Sprite.fromURL(src1, createSprite(1),{"width":50,"height":72});
});
function createSprite(i) {
return function(sprite) {
sprite.set({
left: i * 100 + 50,
top: i * 100 + 50,
hasBorders: false,
padding: 0,
});
canvas.add(sprite);
setTimeout(function() {
sprite.play();
}, fabric.util.getRandomInt(1, 10) * 100);
};
}
(function render() {
canvas.renderAll();
fabric.util.requestAnimFrame(render);
})();
</script>
</body>
</html>
(I've found the only way I can get this demo to work is in FF and if the svg is hosted locally, due to SecurityError. Which stopped me making a working fiddle/jsbin)
Related
I've been trying to get this fairly simple program to work and am running into performance problems.
I'm trying to make thousands of tiny colored dots on a canvas. Creating so many new paths is slowing down my computer before I am able to get the amount that I want on the canvas, and then crashes when I try to export the canvas as an SVG. I looked into using symbols, but I need the colors of each dot to be different.
The goal is for every color and position to be completely random and unique, and to have the dots completely cover the canvas. The canvas will eventually need to be printed 55 inches by 75 inches, so I will want the circles to be of high enough resolution that they don't look pixellated when printed. This can mean either being able to export to a high enough raster resolution or to export to a vector.
I'm using paper.js because I figured that it would be best to render the dots as vector graphics so that I can print them at high quality when I need to, but is there a better way to do this?
Thanks.
the html below is everything (except for the paper.js library).
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/style.css">
<!-- Load the Paper.js library -->
<script type="text/javascript" src="js/paper.js"></script>
<!-- Define inlined PaperScript associate it with myCanvas -->
<style type="text/css">
html,
body {
margin: 0;
overflow: hidden;
height: 100%;
}
/* Scale canvas with resize attribute to full size */
canvas[resize] {
width: 550px;
height: 750px;
background-color: #39ff14;
}
</style>
<script type="text/paperscript" canvas="myCanvas">
paper.install(window);
tool.fixedDistance = .1;
var layer = project.activeLayer;
function onMouseMove(event) {
var radius = (1 * Math.random()) + .5;;
var path = new Path.Circle({
center: Point.random() * view.size,
radius: radius,
fillColor: "#000000".replace(/0/g,function(){return (~~(Math.random()*16)).toString(16);}),
})
}
// START DOWNLOAD BUTTON &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
function downloadDataUri(options) {
if (!options.url)
options.url = "http://download-data-uri.appspot.com/";
$('<form method="post" action="' + options.url
+ '" style="display:none"><input type="hidden" name="filename" value="'
+ options.filename + '"/><input type="hidden" name="data" value="'
+ options.data + '"/></form>').appendTo('body').submit().remove();
}
$('#export-button').click(function() {
var svg = project.exportSVG({ asString: true });
downloadDataUri({
data: 'data:image/svg+xml;base64,' + btoa(svg),
filename: 'export.svg'
});
});
// END DOWNLOAD BUTTON &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
</script>
</head>
<body>
<canvas id="myCanvas" resize></canvas>
<input type="button" value="Download as SVG" id="export-button">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<!-- <script src="js/scripts.js"></script> -->
</body>
</html>
So I thought that the code
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Log Canvas Width</title>
<style>
#canvas {
background: #888888;
width: 600px;
height: 600px;
}
</style>
<script>
function draw() {
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
document.write(canvas.width);
}
</script>
</head>
<body onload="draw();">
<canvas id='canvas'>
Canvas not supported
</canvas>
</body>
</html>
prints 300 rather than 600 because <body onload="draw();"> makes the script run at page loading, and at that time the canvas has not yet caught the revised value (600).
But then I modify the code to:
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Log Canvas Width</title>
<style>
#canvas {
background: #888888;
width: 600px;
height: 600px;
}
</style>
</head>
<body>
<canvas id='canvas'>
Canvas not supported
</canvas>
<script type="text/javascript">
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
document.write(canvas.width);
</script>
</body>
</html>
Now I'm imagining that the script runs after the canvas has taken the attribute from the embedded style and that I will see 600. Not true. I still get 300, even though the canvas duly has width = 600. What is happening?
Default width of canvas is 300 x 150 [Ref]. Canvas does not consider css defined with. Either you defined width/heigh attributes or assign those values as properties of canvas element.
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
alert(canvas.width);
<canvas id='canvas' width='600'>
Canvas not supported
</canvas>
OR
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
canvas.width = 600;
alert(canvas.width);
<canvas id='canvas'>
Canvas not supported
</canvas>
canvas.width and canvas.style.width are two different things. In most of the cases, they should be equal, but they can also be different for achieving various effects. 300 you're getting is the canvas default width.
canvas.width is the actual number of pixels that are available inside the canvas, while canvas.style.width is the width of the HTML element, thus you can see stretching, pixelation, etc, if the two numbers are different.
Here are a couple of answers that describe the issue in more detail:
https://stackoverflow.com/a/28142612/965907
https://stackoverflow.com/a/34539170/965907
https://stackoverflow.com/a/28879318/965907
I found that setting the canvas width and height equal to the style width and height helped me with the calculations later.
Like:
canvas.width = canvas.getBoundingClientRect().width;
canvas.height = canvas.getBoundingClientRect().height;
this is my first time here. I load a SVG with Javascript into an HTML document. I need to replace the color of this SVG (it's a black image with transparency), which is placed into a canvas; however, when I put the css (style), nothing happens.
This is my code:
<!DOCTYPE html>
<html>
<head>
<title>TEST CANVAS</title>
<script>
function draw_img(){
var img = document.getElementById("test");
test.width = 300;
test.height = 300;
var ctx = test.getContext('2d');
var source = new Image();
source.src = './field/image.svg';
source.onload = function(){
ctx.drawImage(source, 0, 0);
}
}
</script>
</head>
<style>
canvas#test {
fill:darkred;
}
</style>
<body onload = "draw_img();">
<h1>TEST</h1>
<canvas id="test"></canvas>
</body>
</html>
What's wrong with it? Sorry for my bad English and thanks in advance
Canvasses are bitmap images. You can't apply CSS styles to them and expect that to change their colour. Once the SVG is rendered into the Canvas, it's contents are fixed, and can't be changed (except by pixel manipulation).
If you want to manipulate the colours of your SVG, you should inline it.
<style>
svg#test {
fill:darkred;
}
</style>
<body>
<h1>TEST</h1>
<svg id="test">
<rect width="50" height="50"/>
</svg>
</body>
Demo here
I have a html5 page. It uses JQuery and sketch.js (for free drawing). I am NOT going to connect it to any web server. At this moment, I would like to be use this javascript as desktop application. My purpose is to copy image from one canvas to the other canvas in the same page. After draw something by free hand, I could see url is copied to textarea, but no picture after clicking Show URL link. Could someone give me hints how to make an copy of image from one canvas to the other?
/1/ Source codes, one need to add html tag in the beginning, do not forget <>
<head>
<title>sketch and free hand drawing</title>
<!--[if IE]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js">
</script>
<![endif]-->
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="image/png"/>
<script src="js/jquery-1.11.0.min.js"></script>
<script src="js/sketch.js"></script>
/2/One need to add /head above. do not forget <>
<body>
<script>
function toDo(){
console.log(document.getElementById("colors_sketch").toDataURL("image/png"));
document.getElementById("cvs").value=document.getElementById("colors_sketch").toDataURL("image/png");
document.getElementById("txt").value=document.getElementById("colors_sketch").toDataURL("image/png");
}
</script>
<div class="tools">
Download
</div>
<div class="tools">
show URL
</div>
<textarea id="txt"></textarea>
<hr/>
<canvas id="colors_sketch" width="800" height="300">hello</canvas>
<hr/>
<canvas id="cvs" width="800" height="300"></canvas>
<script type="text/javascript">
$(function() {
$.each(['#f00', '#ff0', '#0f0', '#0ff', '#00f', '#f0f', '#000', '#fff'], function() {
$('#colors_demo .tools').append("<a href='#colors_sketch' data-color='" + this + "' style='width: 10px; background: " + this + ";'></a> ");
});
$.each([3, 5, 10, 15], function() {
$('#colors_demo .tools').append("<a href='#colors_sketch' data-size='" + this + "' style='background: #ccc'>" + this + "</a> ");
});
$('#colors_sketch').sketch();
});
/3/ one need to add /script above and /body above and /html above do not forget <>
To move an image from one canvas to another, you can simply use drawImage
destinationContext.drawImage(sourceCanvas,0,0);
The pixels from the source canvas will be drawn onto the destination canvas.
A Demo: http://jsfiddle.net/m1erickson/2hb56/
I tried modifying your code, but it appears you also have a design issue.
SketchJS will erase your copied image in preparation for it's own drawings (the copied image is erased).
Example code copying pixels from one canvas to another:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script src="http://code.jquery.com/jquery.min.js"></script>
<script src="sketch.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
// get references to canvases and contextx
sourceCanvas=document.getElementById("source");
sourceContext=sourceCanvas.getContext("2d");
destinationCanvas=document.getElementById("destination");
destinationContext=destinationCanvas.getContext("2d");
// draw a test image into the source canvas
var testImg=new Image();
testImg.onload=function(){
sourceContext.drawImage(testImg,0,0);
}
testImg.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house-icon.png";
// when the button is clicked
// copy the source canvas onto the destination canvas
$("#copy").click(function(){
destinationContext.drawImage(sourceCanvas,0,0);
})
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="source" width=256 height=256></canvas><br>
<button id="copy">Copy canvas above to canvas below</button><br>
<canvas id="destination" width=256 height=256></canvas>
</body>
</html>
How can I display whole image in circulr shape using Javascript or HTML5. I tried the code below but with this code only part of the image will be converted into circular shape. How can I make the whole display in circular shape?
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
<script type="text/javascript" >
</script>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<div id="myCanvas"></div>
<script>
var ctx = document.getElementById('myCanvas').getContext("2d");
ctx.arc(100,100, 50, 0, Math.PI*2,true); // you can use any shape
ctx.clip();
var img = new Image();
img.addEventListener('load', function(e) {
ctx.drawImage(this, 0, 0, 200, 300);
}, true);
img.src="images/hospital_review_profile_placeholder.png";
</script>
</body>
</html>
Instead of using ctx.clip(), you would resize and reposition your image to fit in your circle.
Here is code that will resize your image to its largest size that will fit in the circle.
Then the code positions the resized image properly in the circle.
Here is a Fiddle --- http://jsfiddle.net/m1erickson/s6MzZ/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var radius=50; // circle radius
var fullWidth=200; // actual width of image in pixels
var fullHeight=300; // actual height of image in pixels
var centerX=100; // center X coordinate of the circle
var centerY=100; // center Y coordinate of the Circle
// the image must be resized to fit into the circle
// Call CalcResizedImageDimensions() to get the resized width/height
var size=CalcResizedImageDimensions(radius,fullWidth,fullHeight);
var rectX=centerX-size.width/2; // the X coordinate of the resized rectangle
var rectY=centerY-size.height/2 // the Y coordinate of the resized rectangle
ctx.beginPath();
ctx.arc(centerX,centerY,radius,0,Math.PI*2,true);
// I illustrate with just a rectangle
// you would drawImage() instead
ctx.rect(rectX,rectY,size.width,size.height);
ctx.stroke();
function CalcResizedImageDimensions(r,w,h){
var d=2*r;
var newH=(d*h)/Math.sqrt(w*w+h*h);
var newW=w/h*newH;
return({width:newW,height:newH});
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=200 height=200></canvas>
</body>
</html>