Clear and re-draw using svg.js - javascript

I want to draw some elements using svg.js then clear the canvas and draw new elements. I'm using draw.clear() but when I re-draw the elements, they aren't visible. Is this approach correct or am I missing something? I also tried remove().
var width = 500;
var height = 500;
var pos_x = 0;
var pos_y = 0;
var texto = [];
var grupo = [];
var rect = [];
var clip = [];
var random_rotation = [];
var latino = 'ABCDEFGHIJKLMNOPQRSTUVXYZ'.split('');
var cirilico = 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ'.split('');
var hebreo = 'אבגדהוזיךכל םמןנסעףפפצקחט '.split('');
var griego = 'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨ'.split('');
var arabe = 'ابتثجحخدذرزسشصضطظعغفقكلمنهويةءأإ'.split('');
var coreano = 'ㅏㅑㅓㅕㅗㅛㅜㅠㅡㅣㅐㅒㅔㅖㅘㅙㅚㅝㅞㅟㅢㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎㄲㄸㅃㅆㅉㄳㄵㄶㄺㄻㄿㄽㄾㄿㅀㅄ'.split('');
var glagolitico = 'ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮ'.split('');
var hiragana = 'あかさたなはまやらわがざだばぱいきしちにひみり(ゐ)ぎじぢびぴうくすつぬふむゆるぐずづぶぷえけせてねへめれ(ゑ)げぜでべぺおこそとのほもよろをごぞどぼぽ'.split('');
var katakana = 'アカサタナハマヤラワガザダバパヴァイキシチニヒミリ(ヰ)ギジヂビピヴィウクスツヌフムユルグズヅブプヴエケセテネヘメレ(ヱ)ゲゼデベペヴェオコソトノホモヨロヲゴゾドボポヴォ'.split('');
var sistemas = [latino, cirilico, hebreo, griego, arabe, coreano, glagolitico, hiragana, katakana];
var alfabeto = [];
var letra = [];
var draw = SVG().addTo('.container').size(width, height).attr({id: 'svg'});
function getRndInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function getRndFloat(min, max) {
return (Math.random() * (max - min)) + min;
}
// Create symbols
function grafema(){
for (var i = 0; i <= 3; i++){
alfabeto[i] = getRndInteger(0, sistemas.length - 1);
letra[i] = sistemas[alfabeto[i]][getRndInteger(0, sistemas[alfabeto[i]].length - 1)];
random_rotation[i] = getRndInteger(0, 360);
texto[i] = draw.text(letra[i])
.font({
family: 'Arial Unicode MS',
size: 500,
anchor: 'middle'
})
.transform({
translateX: width/2,
translateY: (height/2) * -1,
rotate: random_rotation[i],
scale: getRndFloat(0.5, 0.6)
});
grupo[i] = draw.group()
.attr({
id: 'letra ' + i
});
grupo[i].add(texto[i]);
rect[i] = draw.rect(200, 200)
.attr({
x: pos_x,
y: pos_y,
})
.transform({
rotate : random_rotation[i],
});
pos_x = pos_x + 200;
if (pos_x > 200) {
pos_x = 0;
pos_y = pos_y + 200;
}
clip[i] = draw.clip().add(rect[i]);
grupo[i].clipWith(clip[i]);
}
}
grafema();
draw.clear();
grafema();
This is a simplified version of a program I'm trying to create. In the future I would like to clear and re-draw whenever the user makes a click.

The problem in your code is not the clear() method. You are using global variables pos_x and pos_y and you are incrementing them. In your second drawing, the images are outside the visible area. To solve your issue, initialise those variables in the beginning of your grafema function:
// ...
function grafema() {
pos_x = 0;
pos_y = 0;
for (var i = 0; i <= 3; i++) {
// ...
Example of execution with infinite drawings:
https://jsbin.com/mehuholiwo/edit?js,output

Related

Uncaught TypeError: (((item.value + 1) / total) * 100).floor is not a function

This code is running good here: https://jsfiddle.net/petersirka/fycx4kr1/
but not on other code editor like codepen or vscode getting error on line 33
//HTML
<svg id="svg" width="600" height="600"></svg>
//Javascript
function Donut(cx, cy, radius, data) {
function arcradius(cx, cy, radius, degrees) {`enter code here`
var radians = (degrees - 90) * Math.PI / 180.0;
return {
x: cx + (radius * Math.cos(radians)),
y: cy + (radius * Math.sin(radians))
};
}
var decimals = 4;
var total = 0;
var arr = [];
var beg = 0;
var end = 0;
var count = 0;
var half = radius / 2;
var midpoint = radius / 2.4;
for (var i = 0; i < data.length; i++)
total += data[i].value;
for (var i = 0; i < data.length; i++) {
var item = data[i];
var tmp = {};
var p = (((item.value + 1) / total) * 100).floor(2);
count += p;
if (i === length - 1 && count < 100)
p = p + (100 - count);
end = beg + ((360 / 100) * p);
tmp.index = i;
tmp.value = item.value;
tmp.data = item;
var b = arcradius(cx, cy, radius, end);
var e = arcradius(cx, cy, radius, beg);
var la = (end - beg) <= 180 ? 0 : 1;
tmp.d = ['M', b.x.floor(decimals), b.y.floor(decimals), 'A', radius, radius, 0, la, 0, e.x.floor(decimals), e.y.floor(decimals)].join(' ');
arr.push(tmp);
beg = end;
}
return arr;
}
// USAGE
(function(svg) {
var data = [{
value: 45
}, {
value: 25
}, {
value: 30
}];
var centerX = 300;
var centerY = 300;
var radius = 250;
var color = ['#7400b8', '#ff006e', '#3a86ff'];
var arr = Donut(centerX, centerY, radius, data);
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
svg.asvg('<g><path d="{0}" stroke="{1}" fill="none" stroke-width="50" /></g>'.format(item.d, color[i]));
}
})(document.getElementById('#svg'));
I know Math.Floor is a function because I've used it before and I looked it up. Did I mess something up in the code? Thanks.
Sorry if this question is a little vague, I'm still learning (as you can see :p).
If you want to convert the line
var p = (((item.value + 1) / total) * 100).floor(2);
into an integer with the floor function, you must write it like this:
var p = Math.floor(((item.value + 1) / total) * 100);
So the term you want to apply the Math.floor() function is inside the brackets.
I don't know what that (2) at the end means though...

Can this script be used to create multiple SVG elements?

I have the following JavaScript that creates a graph using snap SVG.
However I need to create 4 SVG's in total and I was wondering if I could use only this script for it? And if so, how would I go about adjusting it? Or is it necessary with 4 seperate scripts to create the 4 SVG's?
In short; what's the best way going about this?
Thanks in advance.
The script:
//#SVG
var price = [0,-50, -100, -130, -150, -200];
//CHART VALUES
var chartH = $('#svg').height();
var chartW = $('#svg').width();
// PARSE PRICES TO ALIGN WITH BOTTOM OF OUR SVG
var prices = [];
for (i = 0; i < price.length; i++) {
prices[i] = price[i] + $('#svg').height();
}
function draw() {
//DEFINE SNAP SVG AND DETERMINE STEP NO.
var paper = Snap('#svg');
var steps = prices.length;
// EVENLY DISTRIBUTE OUR POINTS ALONG THE X AXIS
function step(i, chartW) {
return chartW / prices.length * i;
}
var points = [];
var breakPointsX = [];
var breakPointsY = [];
var point = {};
for (i = 1; i < prices.length; i++) {
//CALCULATE CURRENT POINT
var currStep = step(i, chartW);
var y = prices[i];
point.x = Math.floor(currStep);
point.y = y;
//CALCULATE PREVIOUS POINT
var prev = i - 1;
var prevStep = step(prev, chartW);
var prevY = prices[prev];
point.prevX = Math.floor(prevStep);
point.prevY = prevY;
if (point.prevX === 0 || point.prevY === 0){
point.prevX = 15;
point.prevY = chartH - 0
}
// SAVE PATH TO ARRAY
points[i] = " M" + point.prevX + "," + point.prevY + " L" + point.x + "," + point.y;
// SAVE BREAKPOINTS POSITION
var r = 30;
breakPointsX[i] = point.x;
breakPointsY[i] = point.y;
}
// DRAW LINES
for (i = 0; i < points.length; i++) {
var myPath = paper.path(points[i]);
var len = myPath.getTotalLength();
myPath.attr({
'stroke-dasharray': len,
'stroke-dashoffset': len,
'stroke': '#3f4db3',
'stroke-linecap': 'round',
'stroke-width': 6,
'stroke-linejoin': 'round',
'id': 'myLine' + i,
'class': 'line'
});
}
// DRAW BREAKPOINTS
for (i = 0; i < points.length; i++) {
var circle = paper.circle(breakPointsX[i], breakPointsY[i], 5);
circle.attr({
'fill': '#fff',
'stroke': '#3f4db3',
'stroke-width': 3,
'id': 'myCirc' + i,
'class':'breakpoint'
});
}
// DRAW COORDINATE SYSTEM
var xAxis = paper.path('M0,'+chartH+'L'+chartW+","+chartH);
var yAxis = paper.path('M0,'+chartH+'L0,0');
var xOff = xAxis.getTotalLength();
var yOff = yAxis.getTotalLength();
var start = (prices.length*250+"ms");
yAxis.attr({
'stroke':'black',
'stroke-width':10,
'stroke-dasharray':yOff,
'stroke-dashoffset':yOff,
'id':'yAxis'
});
xAxis.attr({
'stroke':'black',
'stroke-width':5,
'stroke-dasharray':xOff,
'stroke-dashoffset':xOff,
'id':'xAxis'
});
console.log(start);
$('#yAxis').css({
'-webkit-transition-delay':start,
'-webkit-transition':'all 200ms ease-in'
});
$('#xAxis').css({
'-webkit-transition-delay':start,
'-webkit-transition':'all 200ms ease-in'
});
$('#xAxis').animate({
'stroke-dashoffset':'0'
});
$('#yAxis').animate({
'stroke-dashoffset': '0'
});
}
function animate(){
for (i=0;i<prices.length;i++){
var circ = $('#myCirc'+i);
var line = $('#myLine'+i);
circ.css({
'-webkit-transition':'all 550ms cubic-bezier(.84,0,.2,1)',
'-webkit-transition-delay':375+(i*125)+"ms"
});
line.css({
'-webkit-transition':'all 250ms cubic-bezier(.84,0,.2,1)',
'-webkit-transition-delay':i*125+"ms"
});
line.animate({
'stroke-dashoffset':0
});
circ.css({
'transform':'scale(1)'
});
}
}
var alreadyPlayed = false;
$(window).load(function(){
draw();
animate();
});

HTML5 Canvas | Bouncing Balls | Looping through an image array and placing different background images on each ball, centered

I am having a bit of a nightmare applying different background images onto balls that bounce around in the canvas under the effect of gravity and the bounds of my canvas, eventually settling down and stacking at the bottom.
I have created an image array, that I am trying to loop through and create a ball for each image, where the image becomes a centred background.
I can centre the image, but this makes the balls appear to leave the bounds of my canvas. So have reverted that change.
I am unable to get the background image to be different from the previous ball. Where the image shown on all balls is the last image in the array. However the number of balls created does reflect the number of images in the array.
Here is a link to a codepen:
https://codepen.io/jason-is-my-name/pen/BbNRXB
html, body{
width:100%;
height:100%;
margin: 0;
padding: 0;
background: #333333;
}
*{
margin: 0;
padding: 0;
}
.container {
width: 410px;
height: 540px;
}
#ball-stage{
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<canvas id="ball-stage" ></canvas>
</div>
<script>
/*
/*
* Created by frontside.com.au
* Amended by Jason
*/
$(document).ready(function () {
$.ajaxSetup({
cache: true
});
var url1 = "https://code.createjs.com/easeljs-0.6.0.min.js";
$.getScript(url1, function () {
new App();
})
});
function App() {
var self = this;
self.running = false;
self.initialized = false;
var stageClicked = false;
var stage, canvas;
var canvasWidth = 410;
var canvasHeight = 540;
var bounce = -0.75;
var balls = [];
var _gravityY = 1;
var _gravityX = 0;
var FPS = 30;
var infoText, detailsText;
var ballsInitalized = false;
var iOS = navigator.userAgent.match(/(iPod|iPhone|iPad)/);
self.initialize = function () {
toggleListeners(true);
self.initCanvas();
self.initGame();
};
var toggleListeners = function (enable) {
if (!enable) return;
};
self.refresh = function () {}
self.initCanvas = function () {
canvas = $("#ball-stage").get(0);
stage = new createjs.Stage(canvas);
window.addEventListener('resize', onStageResize, false);
onStageResize();
createjs.Touch.enable(stage);
createjs.Ticker.addListener(tick);
createjs.Ticker.setFPS(FPS);
self.initialized = true;
}
self.initGame = function () {
initBalls(canvasWidth, canvasHeight);
}
var onStageResize = function () {
stage.canvas.width = canvasWidth;
stage.canvas.height = canvasHeight;
}
var initBalls = function (stageX, stageY) {
var imagesArray = ["img-1.png","img-2.png","img-3.png","img-4.png","img-5.png","img-6.png","img-7.png","img-8.png"];
for (var i = 0; i < imagesArray.length; i++) {
console.log(i);
var imageArray = imagesArray[i];
console.log(imageArray);
setTimeout(function () {
var arrayImage = new Image();
console.log(arrayImage);
arrayImage.onload = function(){
addBall(arrayImage, stageX / 2, 0);
}
arrayImage.src = imageArray;
}, i * 1000);
}
}
var addBall = function (img, x, y) {
console.log(img);
var shape = new createjs.Shape();
shape.id = balls.length;
shape.radius = 51.25;
shape.mass = shape.radius;
shape.x = x;
shape.y = y;
shape.vx = rand(-3, 3);
shape.vy = rand(-3, 3);
var image = new Image();
image.src = img;
shape.graphics.beginBitmapFill(img,'repeat').drawCircle(0, 0, shape.radius);
stage.addChild(shape);
balls.push(shape);
}
var numBalls = function () {
return balls.length;
}
var tick = function () {
balls.forEach(move);
for (var ballA, i = 0, len = numBalls() - 1; i < len; i++) {
ballA = balls[i];
for (var ballB, j = i + 1; j < numBalls(); j++) {
ballB = balls[j];
checkCollision(ballA, ballB);
}
}
stage.update();
}
var rotate = function (x, y, sin, cos, reverse) {
return {
x: (reverse) ? (x * cos + y * sin) : (x * cos - y * sin),
y: (reverse) ? (y * cos - x * sin) : (y * cos + x * sin)
};
}
var checkCollision = function (ball0, ball1) {
var dx = ball1.x - ball0.x,
dy = ball1.y - ball0.y,
dist = Math.sqrt(dx * dx + dy * dy);
//collision handling code here
if (dist < ball0.radius + ball1.radius) {
//calculate angle, sine, and cosine
var angle = Math.atan2(dy, dx),
sin = Math.sin(angle),
cos = Math.cos(angle),
//rotate ball0's position
pos0 = {
x: 0,
y: 0
}, //point
//rotate ball1's position
pos1 = rotate(dx, dy, sin, cos, true),
//rotate ball0's velocity
vel0 = rotate(ball0.vx, ball0.vy, sin, cos, true),
//rotate ball1's velocity
vel1 = rotate(ball1.vx, ball1.vy, sin, cos, true),
//collision reaction
vxTotal = vel0.x - vel1.x;
vel0.x = ((ball0.mass - ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x) /
(ball0.mass + ball1.mass);
vel1.x = vxTotal + vel0.x;
//update position - to avoid objects becoming stuck together
var absV = Math.abs(vel0.x) + Math.abs(vel1.x),
overlap = (ball0.radius + ball1.radius) - Math.abs(pos0.x - pos1.x);
pos0.x += vel0.x / absV * overlap;
pos1.x += vel1.x / absV * overlap;
//rotate positions back
var pos0F = rotate(pos0.x, pos0.y, sin, cos, false),
pos1F = rotate(pos1.x, pos1.y, sin, cos, false);
//adjust positions to actual screen positions
// ball1.x = ball0.x + pos1F.x;
setBallX(ball1, ball0.x + pos1F.x)
//ball1.y = ball0.y + pos1F.y;
setBallY(ball1, ball0.y + pos1F.y)
// ball0.x = ball0.x + pos0F.x;
setBallX(ball0, ball0.x + pos0F.x)
// ball0.y = ball0.y + pos0F.y;
setBallY(ball0, ball0.y + pos0F.y)
//rotate velocities back
var vel0F = rotate(vel0.x, vel0.y, sin, cos, false),
vel1F = rotate(vel1.x, vel1.y, sin, cos, false);
ball0.vx = vel0F.x;
ball0.vy = vel0F.y;
ball1.vx = vel1F.x;
ball1.vy = vel1F.y;
}
}
var checkWalls = function (ball) {
if (ball.x + ball.radius > canvas.width) {
// ball.x = canvas.width - ball.radius;
setBallX(ball, canvas.width - ball.radius)
ball.vx *= bounce;
} else
if (ball.x - ball.radius < 0) {
// ball.x = ball.radius;
setBallX(ball, ball.radius)
ball.vx *= bounce;
}
if (ball.y + ball.radius > canvas.height) {
// ball.y = canvas.height - ball.radius;
setBallY(ball, canvas.height - ball.radius)
ball.vy *= bounce;
} else
if (ball.y - ball.radius < 0) {
//ball.y = ball.radius;
setBallY(ball, ball.radius)
ball.vy *= bounce;
}
}
var move = function (ball) {
ball.vy += _gravityY;
ball.vx += _gravityX;
setBallX(ball, ball.x + ball.vx)
setBallY(ball, ball.y + ball.vy)
checkWalls(ball);
}
var setBallX = function (ball, x) {
if (isNaN(ball.pointerID)) {
ball.x = x
}
}
var setBallY = function (ball, y) {
if (isNaN(ball.pointerID)) {
ball.y = y
}
}
var rand = function (min, max) {
return Math.random() * (max - min) + min;
return (Math.random() * max) + min;
}
self.initialize();
return self;
}
window.log = function f() {
log.history = log.history || [];
log.history.push(arguments);
if (this.console) {
var args = arguments,
newarr;
args.callee = args.callee.caller;
newarr = [].slice.call(args);
if (typeof console.log === 'object') log.apply.call(console.log, console, newarr);
else console.log.apply(console, newarr);
}
};
(function (a) {
function b() {}
for (var c = "assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","), d; !!(d = c.pop());) {
a[d] = a[d] || b;
}
})
(function () {
try {
console.log();
return window.console;
} catch (a) {
return (window.console = {});
}
}());
</script>
I have been trapped at this point in the code for about a week now and could really do with some genius' help!
Aims:
Add balls equivalent to the length of the image array.
Each ball with have its respective image as a centred background.
The balls will not leave the bounds of the canvas.
Relevant code:
initBalls()
addBall()
Thanks, Jason.
https://codepen.io/prtjohanson/pen/vPKQBg
What needed to be changed:
for (let i = 0; i < imagesArray.length; i++) {
console.log(i);
const imageArray = imagesArray[i];
setTimeout(function() {
var arrayImage = new Image();
arrayImage.onload = function() {
addBall(arrayImage, stageX / 2, 0);
};
arrayImage.src = imageArray;
}, i * 1000);
}
By the time the setTimeout callback fired, your for loop had already finished and with a var declaration, the for loop iteration has no scope of its own, with a let, each iteration has its own scope like a function does.
If it must run on browsers that don't have let or const keywords, let me know, I can provide a solution for them as well
This will work in IE11 and other browsers that don't support ES6
for (var i = 0; i < imagesArray.length; i++) {
(function(imageArray) {
setTimeout(function() {
var arrayImage = new Image();
arrayImage.onload = function() {
console.log('Add'+i);
addBall(arrayImage, stageX / 2, 0);
};
arrayImage.src = imageArray;
}, i * 1000);
})(imagesArray[i]);
}
To get the images centered, without them going out of the bounds of canvas, use a 2D transform on the beginBitmapFill operation:
var transform = new createjs.Matrix2D();
transform.appendTransform(-shape.radius, -shape.radius, 1, 1, 0);
shape.graphics.beginBitmapFill(img, "repeat", transform).drawCircle(0, 0, shape.radius);
As for there being not as many balls as there are URLs in the array, it seems that sometimes the image source URL prompts "I am not a robot" captcha. If replaced with URL-s under your control, the issue should go away.

FabricJS: big grid objects is blurry

I want to draw a large grid with fabricjs, but it is too blurry. I use fabricJS canvas.toSVG() export to a svg file, and I open the svg file in browser, it's view good. so I think this is most possible likely a bug for edge.
The test code is:
var data = [];
var temp = [0,0,-0.012,-0.012,-0.012,-0.012,-0.012,-0.012,0,0,-0.012,-0.012,0,0.049,0.073,0.049,0.049,0.037,-0.012,-0.012,-0.024,-0.049,-0.024,-0.049,-0.061,-0.012,-0.061,-0.086,0.061,0.146,0.354,0.403,-0.647,-1.88,-1.672,-0.757,-0.33,-0.098,0.024,0.012,0.073,0.122,0.098,0.146,0.183,0.171,0.207,0.232];
for (var i = 0; i < 200; i++) {
data = data.concat(temp);
}
// case 1 : blurry
var canvas1 = new fabric.Canvas("ecg1");
var width = 8000;
var height = 400;
canvas1.setWidth(width);
canvas1.setHeight(height);
var bg1 = getBackgroundPath(width, height);
var ecg1 = getEcgPath(data);
canvas1.add(bg1);
canvas1.add(ecg1);
canvas1.renderAll(); // blurry
// case 2 : ok
var canvas2 = new fabric.Canvas("ecg2");
var data2 = data.slice(0, 3000);
width = 1000;
height = 400;
canvas2.setWidth(width);
canvas2.setHeight(height);
var bg2 = getBackgroundPath(width, height);
var ecg2 = getEcgPath(data2);
canvas2.add(bg2);
canvas2.add(ecg2);
canvas2.renderAll();
// case 3 : blurry
var canvas3 = new fabric.Canvas("ecg3");
canvas3.setWidth(width);
canvas3.setHeight(height);
canvas3.add(new fabric.Group([bg2, ecg2]));
canvas3.renderAll();
function getBackgroundPath(width, height) {
var grid = [];
for (var y = 0; y <= height; y += 10) {
grid.push("M");
grid.push("0");
grid.push(y);
grid.push("H");
grid.push(width);
}
for (var x = 0; x <= width; x += 10) {
grid.push("M");
grid.push(x);
grid.push("0");
grid.push("V");
grid.push(height);
}
return new fabric.Path(grid.join(" "), {
top : 0,
left : 0,
stroke: 'pink',
strokeWidth: 1
});
}
function getEcgPath(data) {
var xm = 2;
var ym = 100;
var max = Math.max.apply(Math, data);
var path = [];
for (var i = 0; i < data.length; i++) {
path.push("L");
path.push(i * xm);
path.push((max - data[i]) * ym);
}
path[0] = "M";
return new fabric.Path(path.join(" "), {
top : 0,
left : 0,
fill : '',
stroke: 'black',
strokeWidth: 1
});
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<canvas id="ecg1"></canvas>
<canvas id="ecg2"></canvas>
<canvas id="ecg3"></canvas>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.3/fabric.min.js" ></script>
</body>
</html>
the result is
Please have further reading here:
http://fabricjs.com/fabric-object-caching
This question is actually easily solvable disabling caching for the ECG line.
If your application needs to draw just a big path or an handfull of them, caching is not necessary.
How caching works?
Caching draw the object on a separate canvas and then reuse that canvas every frame when you move it.
This is way more performing than having to execute multiple fill and stroke operation each frame for many objects, especially when objects are complex.
To avoid performances pitfall the canvas used for caching is limited to 2 mega pixels by default ( you can push it up changing fabric.perfLimitSizeTotal ) and whatever is the mega pixel size, the largest size is limited to 4096 by default ( if you do not need to support ie11 you can make it bigger changing fabric.maxCacheSideLimit ).
In your case the path is smoothly handled by the cpu.
For the grid we need some more code.
var data = [];
var temp = [0,0,-0.012,-0.012,-0.012,-0.012,-0.012,-0.012,0,0,-0.012,-0.012,0,0.049,0.073,0.049,0.049,0.037,-0.012,-0.012,-0.024,-0.049,-0.024,-0.049,-0.061,-0.012,-0.061,-0.086,0.061,0.146,0.354,0.403,-0.647,-1.88,-1.672,-0.757,-0.33,-0.098,0.024,0.012,0.073,0.122,0.098,0.146,0.183,0.171,0.207,0.232];
for (var i = 0; i < 200; i++) {
data = data.concat(temp);
}
// case 1 : blurry
var canvas1 = new fabric.Canvas("ecg1");
var width = 8000;
var height = 400;
canvas1.setWidth(width);
canvas1.setHeight(height);
var bg1 = getBackgroundPath(width, height);
var ecg1 = getEcgPath(data);
canvas1.add(bg1);
canvas1.add(ecg1);
canvas1.renderAll(); // blurry
function getBackgroundPath(width, height) {
var grid = [];
for (var y = 0; y <= height; y += 10) {
grid.push("M");
grid.push("0");
grid.push(y);
grid.push("H");
grid.push(width);
}
for (var x = 0; x <= width; x += 10) {
grid.push("M");
grid.push(x);
grid.push("0");
grid.push("V");
grid.push(height);
}
return new fabric.Path(grid.join(" "), {
top : 0,
left : 0,
stroke: 'pink',
strokeWidth: 1
});
}
function getEcgPath(data) {
var xm = 2;
var ym = 100;
var max = Math.max.apply(Math, data);
var path = [];
for (var i = 0; i < data.length; i++) {
path.push("L");
path.push(i * xm);
path.push((max - data[i]) * ym);
}
path[0] = "M";
return new fabric.Path(path.join(" "), {
top : 0,
left : 0,
fill : '',
stroke: 'black',
strokeWidth: 1,
objectCaching: false,
});
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<canvas id="ecg1"></canvas>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.3/fabric.min.js" ></script>
</body>
</html>
#AndreaBogazzi
Thanks your answer. After I use fabric.Object.prototype.objectCaching = false, it's shows good.
In my application, the draw grid code is as follows.
var data = [];
var temp = [0,0,-0.012,-0.012,-0.012,-0.012,-0.012,-0.012,0,0,-0.012,-0.012,0,0.049,0.073,0.049,0.049,0.037,-0.012,-0.012,-0.024,-0.049,-0.024,-0.049,-0.061,-0.012,-0.061,-0.086,0.061,0.146,0.354,0.403,-0.647,-1.88,-1.672,-0.757,-0.33,-0.098,0.024,0.012,0.073,0.122,0.098,0.146,0.183,0.171,0.207,0.232];
for (var i = 0; i < 200; i++) {
data = data.concat(temp);
}
// case 1 : blurry
var canvas1 = new fabric.Canvas("ecg1");
var width = 8000;
var height = 400;
canvas1.setWidth(width);
canvas1.setHeight(height);
var bg11 = getBackgroundDot(width, height);
var bg12 = getBackgroundPath(width, height);
var ecg1 = getEcgPath(data);
canvas1.add(bg11);
canvas1.add(bg12);
canvas1.add(ecg1);
canvas1.renderAll(); // blurry
function getBackgroundDot() {
var dotLineWidth = 2;
var dot = [];
dot.push("M 0 0");
for (var y = 0; y <= height; y += 10) {
if (y % 50 == 0) {
continue;
}
dot.push("M");
dot.push("0");
dot.push(y);
dot.push("H");
dot.push(width);
}
var sda = [0, 10];
for (var i = 1; i < 5; i++) {
sda.push(dotLineWidth);
sda.push(8);
}
return new fabric.Path(dot.join(" "), {
top : 0,
left : 0,
stroke: 'pink',
strokeWidth: dotLineWidth,
strokeDashArray: sda
});
}
function getBackgroundPath(width, height) {
var grid = [];
for (var y = 0; y <= height; y += 50) {
grid.push("M");
grid.push("0");
grid.push(y);
grid.push("H");
grid.push(width);
}
for (var x = 0; x <= width; x += 50) {
grid.push("M");
grid.push(x);
grid.push("0");
grid.push("V");
grid.push(height);
}
return new fabric.Path(grid.join(" "), {
top : 0,
left : 0,
stroke: 'pink',
strokeWidth: 1
});
}
function getEcgPath(data) {
var xm = 2;
var ym = 100;
var max = Math.max.apply(Math, data);
var path = [];
for (var i = 0; i < data.length; i++) {
path.push("L");
path.push(i * xm);
path.push((max - data[i]) * ym);
}
path[0] = "M";
return new fabric.Path(path.join(" "), {
top : 0,
left : 0,
fill : '',
stroke: 'black',
strokeWidth: 1
});
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<canvas id="ecg1"></canvas>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.3/fabric.min.js" ></script>
</body>
</html>

Javascript Image Transform? [scale and rotate]

I'm looking to build an image transform tool with Javascript. Something that utilizes handles around the image similar to Photoshop and allows the user to scale and rotate. I'm looking to make this work in IE 6 and up and Firefox 3+ and Safari 3+.
Does anyone know of a library or tool that could help with this? I've seen a lot of tools that utilize the Canvas element but that leaves out IT. I've also seen the Raphael library which might work. Any other options out there?
Have a look at this rotorzoom.
It rotates it zooms it's fast and i can do with a few more hits.
http://codepen.io/hex2bin/pen/tHwhF
var requestId = 0;
var animationStartTime = 0;
var img = new Image();
initimg(img);
dst = document.getElementById("dst").getContext("2d");
dst.drawImage(img, 0, 0, 256, 256);
// read the width and height of the canvas
i = 0;
var imageDataDst = dst.getImageData(0, 0, 1024, 512);
var bufDst = new ArrayBuffer(imageDataDst.data.length);
var buf8Dst = new Uint8ClampedArray(bufDst);
var data32Dst = new Uint32Array(bufDst);
var data32Src = new Uint32Array(256*256);
var scan1=0;
var scan4=0
// fill the source array with the image
for (var y = 0; y < 256; ++y) {
scan4=y*1024*4;
for (var x = 0; x < 256; ++x) {
data32Src[scan1++] =
(255 << 24) + // alpha
(imageDataDst.data[scan4+2] << 16) + // blue
(imageDataDst.data[scan4+1] << 8) + // green
imageDataDst.data[scan4]; // red
scan4=scan4+4;
}
}
animationStartTime = window.performance.now();
requestId = window.requestAnimationFrame(animate);
var j=0;
function animate(time) {
var height=512;
var width=1024;
j=j+1;
var timestamp = j / 100;
var pos;
var startY = 128;
var startX = 128;
var i=0;
var scaledHeight = 512 + Math.sin(timestamp*1.4) * 500;
var scaledWidth = 512 + Math.sin(timestamp*1.4) * 500
var angleRadians = timestamp;
var deltaX1 = Math.cos(angleRadians) * scaledHeight / 256;
var deltaY1 = Math.sin(angleRadians) * scaledHeight / 256;
var deltaY1x256=deltaY1*256;
var deltaX2 =Math.sin(angleRadians ) * scaledWidth / 256;
var deltaY2 =- Math.cos(angleRadians ) * scaledWidth / 256;
var h = height;
while (h--) {
var x =262144+ startX+deltaX1*-512+deltaX2*-256;
var y =262144+ startY+deltaY1*-512+deltaY2*-256;
var y256=y*256;
var w = width;
while (w--) {
//Optimised inner loop. Can it be done better?
pos =(y256>>0&0xff00)+(x>>0&0xff);
data32Dst[i++] =data32Src[pos];
x += deltaX1;
y256 += deltaY1x256;
//end of inner loop
}
startX += deltaX2
startY += deltaY2;
}
imageDataDst.data.set(buf8Dst);
dst.putImageData(imageDataDst, 0, 0);
requestId = window.requestAnimationFrame(animate);
}
function initimg(image1)
{
image1.src = 'data:image/jpeg;base64,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';
}
<body>
<canvas id="dst" width="1024", height="512">
Random Canvas
</canvas>
</body>
Check out Raphael library on Github: https://github.com/DmitryBaranovskiy/raphael

Categories

Resources