I am having difficulties rendering several patterns (each with different texture) in the 2d context of HTML5 canvas.
Assuming I have three separate canvases, two off-screen containing different textures and one for rendering. Let these offline canvases be A and B.
Then:
var patternA = ctx.createPattern(A, "repeat-x");
ctx.fillStyle = patternA;
ctx.fillRect(100,100,20,20);
var patternB = ctx.createPattern(B, "repeat-y");
ctx.fillStyle = patternB;
ctx.fillRect(150,100,20,20);
There should be two 20x20 rectangles, each with their own pattern, however the second rectangle doesn't render at all. I've tried everything to get them working, but to no avail.
Why is that? How should I render multiple tiling textures onto the same canvas?
What browsers are you trying? With FireFox and Chrome, I couldn't get either pattern to render with repeat-x or repeat-y. Instead, I was able to get both to render with just repeat. (See http://jsfiddle.net/ZthsS/1/)
It is possible that browsers have an incomplete implementation of the specification. According to the implementation status at http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-createpattern, IE beta and FF nightly pass all test cases but other browsers don't. I would recommend just using repeat for the time being. You could emulate repeat-x and repeat-y by simply limiting the width of the fillRect to the width of the pattern:
var patternA = ctx.createPattern(A, "repeat");
ctx.fillStyle = patternA;
ctx.fillRect(100,100,20,Math.min(20, A.height));
var patternB = ctx.createPattern(B, "repeat");
ctx.fillStyle = patternB;
ctx.fillRect(150,100,Math.min(20, B.width), 20);
Related
Apologies if this has been answered before, I think I maybe searching for the wrong keywords.
I have an element rendered on the canvas from another library.
Every time stage.update() gets called all my createJS elements get rendered on top.
The element however needs to sit between different createjs objects.
So either I need to find a way to turn this element into a createJs DisplayElement to put it in the correct index position.
Or I need to update just a Container and not the whole stage.
Can someone point me into the right direction?
Thanks
The best approach for this is to render your non-EaselJS content onto another Canvas, and then use it as the source for a Bitmap.
// Non-EaselJS content (whatever you can imagine!)
var canvas1 = document.getElementById("non-easel-canvas");
var context = canvas1.getContext("2d");
context.doStuffWithCanvasAPIs();
// EaselJS content (red background, blue circle)
var stage = new createjs.Stage("easel-canvas");
var bottom = new createjs.Shape();
bottom.graphics.beginFill("red").drawRect(0,0,800,600);
var top = new createjs.Shape();
top.graphics.beginFill("blue").drawCircle(0,0,25);
top.x = top.y = 100;
// Non-easel content added to Easel
var bmp = new createjs.Bitmap(canvas1);
stage.addChild(bottom, bmp, top);
stage.update();
Hope that makes sense. You can also the reverse, and draw the EaselJS content into a non-EaselJS stage using drawImage, and passing the EaselJS canvas as the source. This is how you can mix EaselJS content into things like three.js.
Note that you can also draw any EaselJS content directly without a stage. Each display object (including Container) has a draw() method, which you can call, which draws the object into a supplied context.
http://www.createjs.com/docs/easeljs/classes/DisplayObject.html#method_draw
Cheers,
You have two options here:
Do not use the other library at all, but EaselJS only.
...or...
Use multiple canvases.
Since you need to stack this graphics object in between two easeljs objects, you would need three canvases to accomplish what you're trying to do, and two easeljs stages. Still, this is a hacky workaround for a weird problem.
im trying to do a downscale of an image using canvas to later use the data for a hash compare. however i noticed that the canvas (or at least the simple code i use) uses no mipmap filter resulting in very sharp result and makes the test against another existing hash fail (downscaling the image in gimp using linear works as expected). the code i use to downscale is
var canvas = document.createElement("canvas");
canvas.width = width; canvas.height = height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, width, height);
return context.getImageData(0, 0, width, height).data;
this results in this image (left) to the expected (right)
how can i get the canvas to downscale linear?
The new canvas draft specify a way to set re-sampling/interpolation for the canvas. The current method is always bi-linear, or nearest-neighbor if imageSmoothingEnabled = false (both methods are for both up-scaling and down-sampling). The new property is called imageSmoothingQuality:
context . imageSmoothingQuality [ = value ]
The value can be "low", "medium" and "high" (for example something like bi-cubic/Lanczos). However, no browsers has yet implemented this at the moment of writing this and the actual algorithms used for each value is not mandated.
The alternative approaches is to manually re-sample when you need changes above 50% using multiple steps, or to implement a re-sampling algorithm.
Here is an example of multiple steps to achieve bi-cubic quality level (and avoids initial CORS problems), as well as one showing the Lanczos algorithm (need CORS requirements to be met).
In addition to that you can apply sharpening convolution to compensate for some of the lost sharpness.
SVG stacking is a technique for stuffing multiple SVG images (like icons) into a single file, to enable downloading sets of icons in a single HTTP request. It's similar to a PNG sprite, except much easier to change/maintain.
The SVG to display is selected using the # fragment identifier in the SVG url. The technique is explained here.
While this technique is arguably on shaky grounds in terms of browser support, (and Chrome doesn't support it all in CSS background-image) it works surprisingly well in most browsers if done using an <img> tag. It works in IE9+, Chrome, and Firefox as an <img> tag, so a fallback to PNG is only required if you need to support much older browsers like IE8.
Except... Safari is a bit of a problem. Even though Safari supports SVGs back to version 5 and below, SVG stacking just doesn't work in versions < 7.1. A blank space is displayed where the icon should be.
So, as of now a fallback is probably necessary. But how can we use feature detection to determine whether we need to fallback to PNG sprites (or at least hide the SVG icon so that a blank space doesn't appear.) ?
The various articles discussing SVG stacks talk about providing fallback for browsers which don't support SVGs. Essentially, the most common technique is to simply use Modernizer to detect if SVGs are supported, and if not, use PNGs, as demonstrated here.
But as far as I can see, nobody is discussing the case where a browser DOES support SVGs, but doesn't support SVG stacking. And as far as I know, at least Safari 5 thru 7.0 fall into that category: these browsers support SVGs, but apparently don't support the :target pseudo selector that enables SVG stacking to work.
So how can this condition be detected? Do we have to rely on user agent sniffing here?
Interesting question!
In general, browser cannot answer regarding a feature it doesn't know about. However, some trick came to my mind.
When the image is OK it means that the pixels in it are different, right? And if we see a blank space it means, that all the pixels in it are the same, doesn't matter if they are white, transparent or something else.
So, we can load an image into canvas, take the first pixel and compare the rest with it. If somehing different is found, so the feature is supported, otherwise not. Something like the following code:
function isSVGLayersSupported(img)
{
// create canvas and draw image to it
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext("2d").drawImage(img, 0, 0);
// get cancas context and image data
var ctx = canvas.getContext("2d");
var imageData = ctx.getImageData(0, 0, img.width, img.height);
// Processing image data
var data = imageData.data;
var firstR = data[0];
var firstG = data[1];
var firstB = data[2];
var firstAlpha = data[3];
for (var i = 4; i < data.length; i += 4) {
if ((data[i] != firstR) ||
(data[i+1] != firstG) ||
(data[i+2] != firstB) ||
(data[i+3] != firstAlpha))
return true;
}
return false;
}
This question already has answers here:
How to clear the canvas for redrawing
(25 answers)
Closed 8 years ago.
It's a preety straight up and basic question. I think that because that must be a often action there must be made function, but I can't find it? Is there one? If there isn't does anybody know how to do it?
three ways (at least) :
you can clip your canvas : only the non clipped part will be drawn.
to clip you build a path with beginPath, moveTo, lineTo, arcTo, ... arc,
(any path building function) then you call clip() : the part inside the path
is the clipped-in part.
do not forget to save the context before and to restore it after (unless you want a permanent clip).
snippet :
http://jsbin.com/oSoSugAZ/1/
var context=document.getElementById('cv').getContext('2d');
context.fillStyle='#F66';
context.fillRect(150,150, 500,500); // draw big rect in red
context.save();
context.lineWidth=0; // to have precise clip
context.beginPath();
context.moveTo(100,100);
context.lineTo(200,100);
context.lineTo(200,200);
context.lineTo(100,200);
context.closePath();
context.clip();
// here we can only draw within the rect (100,100) (200,200)
context.fillStyle='#FCE'; // pink
context.fillRect(150,150, 500,500); // will get clipped
context.beginPath();
context.fillStyle = '#AAF';
context.arc(150,150, 30, 0,6.2);
context.fill(); // won't get clipped
// do not forget to restore !
context.restore();
you might use globalCompositeOperation to choose a way the pixel you draw interact with existing ones It works for both drawing paths or images. There are too many options to discuss here, it all depend on your needs.
a full example is here :
https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
Note that darker does not work (but it's not usefull anyway, just use normal mode = source-over with low opacity (0.2) and fillRect in black).
another option is to use temporary canvas to make your draws.
It's very easy, especially if you make small helper functions.
function createCanvas(w,h){
var cv = document.createElement('canvas');
cv.width; cv.height = height;
return cv;
}
( in any case you're interested, you can have a look at my small lib to ease working with a canvas :
https://github.com/gamealchemist/CanvasLib/blob/master/canvasLib.js )
You can't. But you can simulate layers with multiple canvas elements with different z-index.
EDIT:
Check this: canvas layers
Are there any open source libraries (JaveScript) that implement even-odd fill rule on canvas.
If I try to implement it myself then how complex would it be (considering general case which has complex curves also) and would it hit on the performance (due to overhead of doing it for each pixel in JaveScript).
What are the methods for converting even-odd fill to non-zero winding (considering a generic solution that will work for every case). Once method I found was to divide the shape into all non-intersecting polygons and fill them separately.
One option is to use SVG and draw the SVG on canvas, but I also found that native SVG rendering is a bit slow on iPad, but is SVG slow even when I draw it on HTML canvas (on iPad)?
Thanks in advance
I came across this question as I was looking for the same some time ago. That is, use a "evenodd" fill-rule inside a HTML canvas.
After a little research, and going through mailing lists and patches, I noticed that, as it turns out, recent versions of both Firefox and Chrome have support for this, but each in a different, browser-specific, way.
In Firefox it is a matter of using the mozFillRule attribute. Example:
//
// Firefox Example
//
// canv has the HTML canvas element
var ctx = canv.getContext("2d");
ctx.fillStyle = "#ff0000";
ctx.mozFillRule = 'evenodd';
ctx.beginPath();
ctx.moveTo(100, 10);
ctx.lineTo(40, 180);
ctx.lineTo(190, 60);
ctx.lineTo(10,60);
ctx.lineTo(160,180);
ctx.closePath();
ctx.fill();
In Chrome, you do it by passing the string evenodd as a parameter to the fill method. Example:
//
// Chrome Example
//
// canv has the HTML canvas element
var ctx = canv.getContext("2d");
ctx.fillStyle = "#ff0000";
ctx.beginPath();
ctx.moveTo(100, 10);
ctx.lineTo(40, 180);
ctx.lineTo(190, 60);
ctx.lineTo(10,60);
ctx.lineTo(160,180);
ctx.closePath();
ctx.fill('evenodd');
These are the two browsers I researched for, so I don't know about the state of this in other browers. Hopefully in the not-so-distant future we will be able to use this feature via the fillRule attibute that is now part of the HTML standard.
See fill() method API:
void ctx.fill();
void ctx.fill(fillRule);
void ctx.fill(path, fillRule);
fillRule can be "nonzero" or "evenodd"
--- "nonzero": The non-zero winding rule, which is the default rule.
--- "evenodd": The even-odd winding rule.
Browser compatibility:
--- IE 11+, Firefox 31+, Chrome are OK.
--- I didn't test on IE 9/10.
--- Use ctx.mozFillRule = 'evenodd'; with old Firefox 30/30-.