i'm working on this graphic visualizer. following is a example code of what i'm doing.
first i create new canvas and there is a simple jQuery click event to add image objects to canvas.and after working on this canvas i need to load data from database, I've managed to save data on database by "Serialization" which default support by fabric-js. and retrieve data as a json object to load in to canvas. what i want is to completely remove current working canvas and load a new with database retrieved data. so here what i've done so far...
(function() {
var canvasOffsetHeight = '400';
var canvasOffsetWidth = '600';
var canvas = new fabric.Canvas('canvas');
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.setHeight(canvasOffsetHeight);
canvas.setWidth(canvasOffsetWidth);
canvas.renderAll();
}
// resize on init
resizeCanvas();
jQuery('.category ul').on('click', 'li', function (e) {
var imgElement = jQuery(this).children("img")[0];
var imgInstance = new fabric.Image(imgElement, {
left: 100,
top: 100,
angle: 0,
opacity: 1
});
canvas.add(imgInstance);
canvas.renderAll();
return false;
});
jQuery('#obj').click(function(){
canvas_data = '{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0}],"background":"rgba(0, 0, 0, 0)"}';
var canvas = new fabric.Canvas('canvas');
canvas.loadFromJSON(canvas_data,canvas.renderAll.bind(canvas));
});
})();
here lets assume "canvas_data" is the data from database.
the problem is when i load data from an object it appears on canvas correctly but soon as i click on them they just vanishing.
i think because main function run onLoad so when i click it triggers the main function and load the previous canvas. what i want is to wipe out old canvas and load new one with database data. please help.
they say "loadFromJSON" automatically does this for us but it seems not working for me.
No need to create another canvas object. So your code in the #obj.click becomes:
jQuery('#obj').click(function(){
canvas_data = '{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0}],"background":"rgba(0, 0, 0, 0)"}';
canvas.loadFromJSON(canvas_data,canvas.renderAll.bind(canvas));
});
Related
I'm trying a basic display of a preloaded image with p5.js library (instantiation mode):
var sketch = function(p) {
var fondo;
p.preload = function() {
fondo = p.loadImage('app/themes/mrg/dist/images/tramas/example.jpg');
};
var viewportWidth = $(window).width();
p.setup = function(){
canvas = p.createCanvas(viewportWidth, 200);
canvas.background(255);
canvas.image(fondo, 0, 0);
};
};
new p5(sketch);
The canvas was created but no image is there.
Here is a working example:
https://stage.margenesdelarte.org/
The canvas is at the end of the page (with white background) but no image is rendered inside.
Image path is right, since there is no error in the console and it can be reached in its place:
https://stage.margenesdelarte.org/app/themes/mrg/dist/images/tramas/example.jpg
What is wrong, and how can I display this image? Thanks!
That's correct version? (I used BASE64 because I didn't want to run a local server)
var sketch = function(p) {
var fondo;
p.preload = function() {
fondo = p.loadImage("data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7");
};
var viewportWidth = 500;
p.setup = function(){
var canvas = p.createCanvas(viewportWidth, 200);
canvas.image(fondo, 0, 0); // doesn't work
p.image(fondo, 0, 0); // works fine
console.log(p.image, canvas.image); //there are different functions
};
};
new p5(sketch);
https://codepen.io/anon/pen/yPENXx?editors=1111
Explanation:
Both p and canvas has a image function but there are different image functions. You have to use p.image(). I think canvas.image() is has some relations with https://p5js.org/reference/#/p5.Image, but that's only my assumptions.
Is your file being localhosted? For p5 to access local files such as images, it needs to be localhosted... I recommend apache
I'm stuck with my code.
Problem: I have canvas and inside it I draw the lines. And after I finished I want that lines to stay in the right place where i left that(before reload website). So I need to send that canvas to mysql data base. But here I stuck. Did I first need to create .png image and then try to send that image information to database? or somehow I can send it right off from code to database by using AJAX? I read a lot of information and I am confused right now.
If I will use method HTMLgetImageData() and HTMLputImageData() then I need to create some real image in my server? or I can take straight from the canvas? and send to mysql databse? :)
so now I have Canvas in html and some script for drawing the lines:
$(".widget_body").on("mousedown", "canvas", function() {
var id = $(this).attr("id");
var canvas = document.getElementById(id);
var canvas,
context,
dragging = false,
dragStartLocation,
snapshot;
fitToContainer(canvas);
function fitToContainer(canvas){
// Make it visually fill the positioned parent
canvas.style.width ='100%';
canvas.style.height='100%';
// ...then set the internal size to match
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
}
function getCanvasCoordinates(event) {
var x = event.clientX - canvas.getBoundingClientRect().left,
y = event.clientY - canvas.getBoundingClientRect().top;
return {x: x, y: y};
}
function takeSnapshot() {
snapshot = context.getImageData(0, 0, canvas.width, canvas.height);
}
function restoreSnapshot() {
context.putImageData(snapshot, 0, 0);
}
function drawLine(position) {
context.beginPath();
context.moveTo(dragStartLocation.x, dragStartLocation.y);
context.lineTo(position.x, position.y);
context.stroke();
}
function dragStart(event) {
dragging = true;
dragStartLocation = getCanvasCoordinates(event);
takeSnapshot();
}
function drag(event) {
var position;
if (dragging === true) {
restoreSnapshot();
position = getCanvasCoordinates(event);
drawLine(position);
}
}
function dragStop(event) {
dragging = false;
restoreSnapshot();
var position = getCanvasCoordinates(event);
drawLine(position);
}
function clearCanvas(event) {
context.clearRect(0, 0, canvas.width, canvas.height);
}
context = canvas.getContext('2d');
context.strokeStyle = 'purple';
context.lineWidth = 4;
context.lineCap = 'round';
canvas.addEventListener('mousedown', dragStart, false);
canvas.addEventListener('mousemove', drag, false);
canvas.addEventListener('mouseup', dragStop, false);
canvas.addEventListener('dblclick', clearCanvas, false);
});
Maybe somebody can suggest something to me? Maybe something about next steps?What should I have to do from this moment?
Well, it depends on whether you're saving the Canvas as a single image or if you're saving each component of it (such as lines, squares, etc).
If you're saving it as a single image, it will be easier to just save the Data URL to your database. Otherwise, create JavaScript objects containing the properties and values of each shape, e.g.:
var line =
{
Name: "Line",
Color: "#3D4AEE",
Shadow: "NULL"
Length: "",
Point: "130, 120"
}
Then convert the object into a JSON String:
var JSONLine = JSON.stringify(line);
Now you have something you can insert into the database.
Now, when you need to retrieve this from the database, so you can redraw it in the browser, all you need to do is lookup the "design", get all the bits that make up that design and redraw them to the Canvas, using the properties of the shapes that you saved.
I'll leave it up to you to figure out how to structure your database to accommodate the different types of shapes, and their relationships to "designs" that are created.
1. You could save the coordinates in a database without reloading the page using AJAX and then fetch the coordinates via AJAX and set them dynamicly in the Javascript. If you want to use a JS Library that makes AJAX-requests easier to use, I recommend jQuery http://api.jquery.com/jquery.ajax/
2. You could convert the canvas to an image using something like
function convertCanvasToImage(canvas) {
var image = new Image();
image.src = canvas.toDataURL("image/png");
return image;
}
And then save the image in a database. However, you won't be able to change the canvas this way, it will be an image. The first way allows you to save the canvas as it is with it's information. Kind of like Photoshop and a .PSD file.
Firstly, you should use Canvas.toDataURL export the data. After that, you can send the data with a FormData via Fetch API.
var fd = new FormData();
fd.append('field', canvas.toDataURL('image/jpg'), 'sketch.jpg');
fetch('/saveSketch', {
method: 'POST',
body: fd,
});
On server side, you need to parse this FormData to retrieve the file. At this time, your files are already available for being saved into database or filesystem.
I'm trying to add Caman.js filter functionality to a paper.js Raster. And in order not to loose image information I want to reset the image data to the original data (_camanImageData) every time before I call Caman by copying it from a cloned raster. The code is like this:
with(paper) {
Raster.prototype._camanImageData = null;
Raster.prototype.filter = function(options) {
var self = this,
ctx = this.getContext(), // caution! This also inits this._canvas (should).
size = this._size;
if( !this._camanOrgImage ) {
this._camanOrgImage = this.clone(false);
} else {
var dst = ctx.createImageData(size.width, size.height);
dst.data.set(this._camanOrgImage.getImageData(new Rectangle(0, 0, size.width, size.height)).data);
this.setImageData(dst);
}
Caman(this._canvas, function () {
for( option in options ) {
var value = options[option];
this[option](value);
}
this.render(function () {
self._changed(129);
});
});
};
}
The first call works fine. The second works apparently on the already modified data.
I call the filter function like this:
raster.filter({
brightness: 50,
saturation: 10,
hue: 20,
});
What do I do wrong?
The problem was with Caman. Caman doesn't reload the changed canvas, if a "data-caman-id" attribute is set in the canvas element. Just delete this before the call to Caman and it works fine:
this._canvas.removeAttribute("data-caman-id");
Caman(this._canvas, function () {
...
The solution came from: How can I change out an image using CamanJS?
I've got multiple images, and I'd like to load them each into a single <canvas> element at different points in time and then manipulate them using CamanJS. I can get the first image to appear like this:
Caman('#canvas-element', '/images/one.jpg');
But then when I subsequently try to update that same element using the following code, it does not work.
Caman('#canvas-element', '/images/two.jpg');
Is there some way to reset/clear/flush the canvas and load new image data into it, or do I really need to create separate <canvas> elements for each image I want to load? I'd prefer a single element because I don't want to eat up all the memory.
Remove the Caman attribute (data-caman-id) from the IMG or CANVAS element, change the image, and then re-render Caman.
document
.querySelector('#view_image')
.removeAttribute('data-caman-id');
const switch_img = '/to/dir/img.png';
Caman("#view_image", switch_img, function() {
this.render();
});
Hope followed code can help others who have same require.
function loadImage(source) {
var canvas = document.getElementById('image_id');
var context = canvas.getContext('2d');
var image = new Image();
image.onload = function() {
context.drawImage(image, 0, 0, 960, 600);
};
image.src = source;
}
function change_image(source) {
loadImage(source);
Caman('#image_id', source, function () {
this.reloadCanvasData();
this.exposure(-10);
this.brightness(5);
this.render();
});
}
Just figured this one out with a lot of trial and error and then a duh moment!
Instead of creating my canvas directly in my html, I created a container and then just did the following:
var retStr = "<canvas id=\"" + myName + "Canvas\"></canvas>";
document.getElementById('photoFilterCanvasContainer').innerHTML = retStr;
Caman("#" + myName + "Canvas", myUrl, function() {
this.render();
});
You want the canvas id to be unique each time you access the Caman function with a new image.
I have a canvas on one page that will be edited by the user (drawn on), and I want that same canvas to appear in the next page they visit. For example, the first page (floorplan.php) is where the user can create a floor plan, and the next page (furnish.php) is where they can drag and drop furniture on the canvas.
I've already checked out this solution, but it doesn't seem to work for me (http://stackoverflow.com/questions/4405336/how-to-copy-contents-of-one-canvas-to-another-canvas-locally)
Here is my JS code from furnish.php: (my original canvas that I want to copy is called just 'canvas'). Also - I didn't have a save function in my floorplan.php code - maybe this is the issue?
<script>
window.onload = function(){
var canvas2 = document.getElementById( 'canvas2' );
var context2 = canvas.getContext( "2d" );
var destX = 0;
var destY = 0;
var imageObj = new Image();
imageObj.onload = function(){
context.drawImage(canvas, destX, destY);
};
imageObj.src = "images/grid.png";
};
$( document ).ready( function()
{
$( '#clear' ).click( function ()
{
context.clearRect( 0, 0, 700, 700);
} );
} );
</script>
You appear to be expecting the variable canvas to be defined on the new page. Keep in mind that when a new page is loaded the previous page (and the javascript objects for that page) are basically gone.
You will need to serialize the canvas image data, and pass it along in the URL (or somewhere) so that it can be reconstituted on the new page. See this SO question about canvas serialization.
You may also wish to consider making the two phases of your floorplan application work on the same page, so that this isn't necessary.