Paperjs rasterize activeLayer with bounds from view - javascript

I've got this fiddle, where I'd like to achieve sort of rasterized thumbnail of canvas view. Everything works ok until some paths overflow view bounds and those overflowed parts also get exported into thumbnail, what is not desired. Only parts that are visible on canvas should be visible in thumb. I've experimented with clipMask, no success unfortunately.
html code
<canvas id="c"></canvas>
<img id="thumb" />
paperscript code
paper.install(window);
var canvas = document.getElementById('c');
paper.setup(canvas);
var style = {
fillColor : 'black'
};
var objects = new Group();
var background = new Path.Rectangle(view.bounds);
background.fillColor = 'red';
var rect = new Path.Rectangle(-10, 20 , 40, 50);
rect.fillColor = style;
objects.addChild(rect);
var rect = new Path.Rectangle(60, -20 , 40, 50);
rect.fillColor = style;
objects.addChild(rect);
var rect = new Path.Rectangle(195, 20 , 40, 50);
rect.fillColor = style;
objects.addChild(rect);
var rect = new Path.Rectangle(60, 195 , 40, 50);
rect.fillColor = style;
objects.addChild(rect);
objects.bringToFront();
view.draw();
var data = project.activeLayer.rasterize().toDataURL();
var img = document.getElementById('thumb');
img.src = data;
Do you guys have any idea how can this be solved?
Thank you very much for any kind of help.

Okay, so I eventually figured it out. Needed to use getSubRaster function to crop out subraster I needed. To find out how much pixels are overflowing from top or left I used project.activeLayer.bounds.x and .y, which are negative, when overflowing from view.
If someone knows more elegant solution, please let me know.
Here's an updated fiddle

Related

Leaflet Overlay with created PNG

I created a png picture and wanted it do display on a leaflet map.
I tried it like in the code below but it does not work.
(net::ERR_FILE_NOT_FOUND)
Any Ideas how i could do this? Here is the code.
var pic = new PNGlib(200, 200, 256);
var background = pic.color(23, 0, 0, 50);
var my_png = pic.getBase64()
var overlay = new L.ImageOverlay( my_png , bounds, {opacity: 0.5,});
mymap.addLayer(overlay);
I think you have a URI problem. You need to add a "data:image" for your image to appear.
MDN data URLs
You can see an example that works on my codesandbox.
var pic = new PNGlib(200, 200, 256);
var background = pic.color(23, 0, 0, 50);
var my_png = pic.getBase64()
const b64ImgUrl = `data:image/png;base64,${my_png}`;
var overlay = new L.ImageOverlay( b64ImgUrl , bounds, {opacity: 0.5,});
mymap.addLayer(overlay);

assign canvas to div, adapt canvas dimensions to div dimenson - how to fix?

I have this example of a canvas as a div background (I forked it from another example, don't remember where I found it):
http://jsfiddle.net/sevku/6jace59t/18/
var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');
var divHeight = document.getElementById('canvas').clientHeight;
var divWidth = document.getElementById('canvas').clientWidth;
function assignToDiv(){ // this kind of function you are looking for
dataUrl = canvas.toDataURL();
document.getElementsByTagName('div')[0].style.background='url('+dataUrl+')'
}
function draw() { // replace with your logic
ctx.fillStyle = "rgb(100, 250, 100)";
ctx.fillRect (10, 10, divWidth-20, divHeight-20);
}
draw()
assignToDiv()
My problem; If I put the dimensions of the div 300 x 150, the canvas does what it is supposed to do. But if I change the dimensions, the canvas is supposed to adapt to the div dimensions. What did I do wrong that this doesn't happen?
PS: I'm a beginner, so please forgive me stupid questions.
It's because if you don't give canvas width and height, it's default to 300x150, so after you get the width and height from div, you should use them to set your canvas' dimensions as well.
Another point worth notice is that you use div.style.background property to set the background image, however, as there's many background related properties (e.g: background-repeat in your jsfiddle, background-position, background-size...), the background can set all of them at once.
When you use div.style.background='url('+dataUrl+')';. It overrides all other background-related properties to initial.
If you want to preserve those properties, you may either reset them after you set style.background, or you can use div.style.backgroundImage to change the background image without affect other background related properties.
jsfiddle
var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');
var divHeight = document.getElementById('canvas').clientHeight;
var divWidth = document.getElementById('canvas').clientWidth;
// VVVV After you get WxH, set the canvas's dimension too.
canvas.width = divWidth;
canvas.height = divWidth;
var div1 = document.getElementById('canvas');
var div2 = document.getElementById('canvas2');
function assignToDiv(div){ // this kind of function you are looking for
var dataUrl = canvas.toDataURL();
div.style.background='url('+dataUrl+')'; // This line will overwrite your background settings.
div.style.backgroundRepeat = 'repeat-x'; // Use this to set background related properties after above.
}
function assignToDivAlt(div){ // this kind of function you are looking for
var dataUrl = canvas.toDataURL();
div.style.backgroundImage = 'url('+dataUrl+')'; // Only set the background-image would have same effect.
}
function draw() { // replace with your logic
ctx.fillStyle = "rgb(100, 250, 100)";
// If you don't set WH, then the canvas would be 300x150, and those
// you drawed but out of boundary are clipped.
ctx.fillRect (10, 10, divWidth-20, divHeight-20);
}
draw()
assignToDiv(div1);
assignToDiv(div2);
canvas {display:none;}
div {
width:600px;
height:550px;
border:1px solid grey;
background-repeat:repeat-x;
}
<canvas></canvas>
<div id="canvas"></div>
<div id="canvas2"></div>

Responsive sizing of my chart in dimple.js is not working

I have an svg component on my page to which I have appended my dimple chart. I want the chart to be sized responsively.
I have referred to this example in the documentation.
But when I use it in a similar fashion in my line chart, it does not seem to work. My code for a line chart is as follows:
var xpoints = chartData["xdata"];//Populated Dynamically
var ypoints = chartData["ydata"];//Populated Dynamically
var dataset = [];
var line1;
for (var i = 0; i < xpoints.length; i++) {
dataset.push({
x : xpoints[i],
y1 : parseFloat(ypoints[i])
});
}
var svg = dimple.newSvg("#" + mychart, "100%", "100%");
var x, y;
var myChart = new dimple.chart(svg, dataset);
myChart.setMargins("60px", "30px", "110px", "70px");
y = myChart.addMeasureAxis("y", "y1");
x = myChart.addCategoryAxis("x", "x");
line1 = myChart.addSeries("First", dimple.plot.line, [ x, y ]);
line1.lineMarkers = true;
var l = myChart.addLegend(65, 10, 510, 20, "right");
myChart.draw(1500);
window.onresize = function () {
myChart.draw(0, true);
};
Is it that I cannot do this in the same window itself and it is absolutely necessary for me to create a new window, as in the example?
The console does not show any errors, the chart is rendered correctly. It's just that the resize function does not work!
Okay, I found my mistake!
Turns out there is no need to create a new window.
It's just that, I had explicitly defined the height and width of the div (#mychart) to which I was appending my svg and these dimensions were in pixels. So the size of the svg remained the same even on window resize - because it was always 100% of a constant pixel value. So the function was actually firing earlier as well, but was ending up with the same dimensions.
I changed the dimensions of my div to percentage values and everything works fine :D

how to create a canvas dynamically in javascript

I have a canvas that you can draw things with mouse.. When I click the button It has to capture the drawing and add it right under the canvas, and clear the previous one to draw something new..So first canvas has to be static and the other ones has to be created dynamically with the drawing that I draw .. What should I do can anybody help
here is jsfiddle
http://jsfiddle.net/dQppK/378/
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
painting = false,
lastX = 0,
lastY = 0;
You can create a new canvas the same way you’d create any element:
var newCanvas = document.createElement('canvas');
Then you can copy over your old canvas:
newCanvas.width = oldCanvas.width;
newCanvas.height = oldCanvas.height;
oldCanvas.parentNode.replaceChild(newCanvas, oldCanvas);
ctx = newCanvas.getContext('2d');
But if you’re just looking to clear your drawing surface, what’s wrong with clearRect?
ctx.clearRect(0, 0, canvas.width, canvas.height);
Or, in your case, another fillRect. Updated demo
here's the function i use for this, it is part of a library i made and use to ease a few things about canvas.
I just put it on github in case other function might be be of use, i'll have to make a readme later...
https://github.com/gamealchemist/CanvasLib
with namespaceing removed, the code is as follow to insert a canvas :
// insert a canvas on top of the current document.
// If width, height are not provided, use all document width / height
// width / height unit is Css pixel.
// returns the canvas.
insertMainCanvas = function insertMainCanvas (_w,_h) {
if (_w==undefined) { _w = document.documentElement.clientWidth & (~3) ; }
if (_h==undefined) { _h = document.documentElement.clientHeight & (~3) ; }
var mainCanvas = ga.CanvasLib.createCanvas(_w,_h);
if ( !document.body ) {
var aNewBodyElement = document.createElement("body");
document.body = aNewBodyElement;
};
document.body.appendChild(mainCanvas);
return mainCanvas;
}

canvas toDataURL not returning a complete image

I'm building a jQuery plugin which watermarks images (and yes, i'm well aware of the multitudinal drawbacks of a javascript/html5 watermarking system but just ignore that for now.) The basic method for each image is:
paste the image to the background of a canvas
add the data for a watermark image over that,
replace the src of the original image with that of the canvas (which now contains the watermark.)
Now it appears to work fine if I replace the image element with the canvas itself.. all of the elements appear on the canvas. But when I get the dataURL of the canvas, everything but the last image drawn onto it appears. I wouldn't even mind except this plugin also needs to replace the links to images as well, and so replace the hrefs with data urls (with the watermark.)
This is the current code:
(function($){
$.fn.extend({
cmark: function(options) {
var defaults = {
type: 'image',
content: 'watermark.png',
filter: 'darker',
scale:300,
box: {
top : 0.5,
left : 0.5,
width : 0.75,
height : 0.75,
bgcolor : '#000000',
bgopacity : 0.5,
fgopacity : 1
},
callback_unsupported: function(obj){
return obj;
}
}
var getScale = function(w, h, scale){
ratio = Math.min(scale/w, scale/h);
scalew = Math.round(ratio*w);
scaleh = Math.round(ratio*h);
return [scalew,scaleh];
}
var options = $.extend(defaults, options);
return this.each(function() {
obj = $(this);
canvas = document.createElement('canvas');
if(!window.HTMLCanvasElement){
return options.callback_unsupported(obj);
}
/* if selecting for images, reset the images. Otherwise,
we're replacing link hrefs with data urls. */
if(obj.attr('src')){
target_img = obj.attr('src');
}
else if (obj.attr('href')){
target_img = obj.attr('href');
}
// get the filetype, make sure it's an image. If it is, get a mimetype. If not, return.
ftype = target_img.substring(target_img.lastIndexOf(".")+1).toLowerCase();
canvasbg = new Image();
canvasbg.onload = function(){
iw = canvasbg.width;
ih = canvasbg.height;
scale = getScale(iw, ih, options.scale);
iw = scale[0];
ih = scale[1];
canvas.setAttribute('width', iw);
canvas.setAttribute('height', ih);
ctx = canvas.getContext('2d');
/* define the box as a set of dimensions relative to the size of the image (percentages) */
bw = Math.round(iw * options.box.width);
bh = Math.round(ih * options.box.height);
// for now the box will only ever be centered.
bx = Math.round((iw * options.box.top) - (bw/2));
by = Math.round(ih * options.box.left - (bh/2));
/* draw the box unless the opacity is 0 */
if(options.box.bgopacity > 0){
ctx.fillStyle = options.box.bgcolor;
ctx.globalAlpha = options.box.bgopacity;
ctx.fillRect(bx, by, bw, bh);
}
wm = new Image();
wm.onload = function(){
ww = wm.width;
wh = wm.height;
scalar = Math.max(bw, bh); // scale to within the box dimensions
scale = getScale(ww, wh, scalar);
ww = scale[0];
wh = scale[1];
ctx.globalCompositeOperation = options.filter;
ctx.drawImage(wm, bx, by, ww, wh);
}
wm.src = options.content;
ctx.drawImage(canvasbg, 0, 0, iw, ih);
obj.replaceWith(canvas);
$('body').append('<img src="'+canvas.toDataURL()+'">');
//obj.attr('src', canvas.toDataURL());
}
canvasbg.src = target_img;
});
}
})
})(jQuery);
I added a line which dumps an image with the data url directly onto the page for testing and this is what I see... on the left is the canvas element, on the right is the image with the data url:
So yeah, this has had me stumped for a couple of days now. I'm probably missing something horribly obvious but I can't see it.
... edited because the example is no longer online. sorry.
First of all, don't build a string buffer that big for a tag.
var img = new Image();
img.src = canvas.toDataURL();
$('body').append(img);
Or if you prefer:
$('body').append($('<img>').attr('src', canvas.toDataURL()))
Second, you are getting there dataURL of the canvas before you draw the watermark. The drawing happens in the wm.onload callback function, which happens when the watermark loads. That may not fire until way after canvasbg.onload fires off, which is where you get the dataURL.
So move the image append into code at the end of the wm.onload callback and you should be good.

Categories