html5 canvas overlay cutout workaround in safari - html

I am trying to create an overlay that can highlight certain portions of the page. The best way I've figured out to do this is to use a canvas fit to the page, draw the shapes I need, and draw a rectangle using this trick:
ctx.rect(canvas.width, 0, 0 - canvas.width, canvas.height);
I'm not sure I can explain this well, so it might be best to look at the jsFiddle example here to get an idea of what I am trying to do.
This works perfectly in every browser except Safari. Is there any way to achieve this effect in Safari?

You can try filling the whole canvas first, then use composite mode to knock out the shapes.
Example:
ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
ctx.fillRect(canvas.width, 0, 0 - canvas.width, canvas.height);
// next shape will punch hole in the draw rectangle above
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = "rgba(0, 0, 0, 1)"; // make sure alpha is 100%
ctx.beginPath();
ctx.moveTo(300, 60);
ctx.arc(300, 60, 50, 0, 2 * Math.PI);
ctx.moveTo(500, 160);
ctx.arc(500, 160, 50, 0, 2 * Math.PI);
drawEllipse(ctx, 103, 23, 100, 30)
drawEllipse(ctx, 503, 23, 100, 30)
ctx.fill();
ctx.globalCompositeOperation = 'source-over'; // reset comp. mode
Modifed fiddle here
Alpha (not the color) will determine how much visible the hole will be.
Hope this helps.

Related

PDFlib - setting stroke and fill opacity (transparency)

Is it possible to set value of alpha channel when providing fill and stroke colors in PDFlib?
$p->setlinewidth(20);
$p->setcolor('fill', 'rgb', 1, 0, 0, null);
$p->setcolor('stroke', 'rgb', 0, 1, 0, null);
$p->rect(0, 0, 100, 100);
$p->fill_stroke();
Is it possible to make rectangle's red fill and thick green border to be semi-transparent?
Is it possible to make rectangle's red fill and thick green border to be semi-transparent?
sure, please use GState for this task. You find a complete sample code within the PDFlib cookbook: Transparent Graphics
/* Save the current graphics state. The save/restore of the current
* state is not necessarily required, but it will help you get back to
* a graphics state without any transparency.
*/
$gstate = $p->create_gstate("opacityfill=.5 opacitystroke=.5");
$p->save();
$p->set_gstate($gstate);
$p->setlinewidth(20);
$p->setcolor('fill', 'rgb', 1, 0, 0, null);
$p->setcolor('stroke', 'rgb', 0, 1, 0, null);
$p->rect(0, 0, 100, 100);
$p->fill_stroke();
$p->restore();
For a powerful path generation, you might use the Path object. See PDFlib 9.2 Documentation as well the samples within PDFlib Cookbook - path objects.
page.drawText(WATERMARK.LABEL, {
x: 180,
y: 400,
size: 30,
font: helveticaFont,
color: rgb(220 / 255, 220 / 255, 220 / 255),
rotate: degrees(-315),
opacity: 0.6
})
// add opacity field only

dynamic updating of HTML5 canvas

in the snippet below
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, 143, (startAngle * Math.PI / 180) - Math.PI / 2, 1.5 * Math.PI);
ctx.strokeStyle = "white";
ctx.lineWidth = 14;
ctx.stroke();
where i is in multiples of 6,i am not able to update the canvas every second(using loops), the appearance should be like of a receding clock.
link to fiddle:https://jsfiddle.net/727q1u7r/3/
In your fiddle, the code within the loop does not refer to startAngle, so each iteration of the loop is drawing exactly the same thing. You probably want to refer to startAngle within the arc call.
However this is not enough by itself, a for loop is not suitable for animation, the whole loop will be completed in a flash and you won't see any changes.
You could use setInterval as shown in this fiddle.
If you are trying to reliably show the system time however, you should look into using Date and possibly using requestAnimationFrame.

Can't get radial gradient

I'm trying to create elipse with radial gradient fill, but flash makes it filled with solid color (the second one - 0xe9afaf)
var mat:Matrix = new Matrix();
mat.createGradientBox(150, 100, 0, 0, 0);
timeField = new Shape();
timeField.graphics.beginGradientFill(GradientType.RADIAL, [0xd35f57, 0xe9afaf], [1, 1], [0,255],mat);
timeField.graphics.lineStyle(3, 0x561717);
timeField.graphics.drawEllipse(GlobalVariables.globalStage.stageWidth / 2 - 75, -50, 150, 100);
timeField.graphics.endFill();
addChild(timeField);
I have no idea what's wrong.
The position of your matrix's gradient box and your ellipse are off center, so you're seeing the solid part of the gradient after all the color has faded out. You're going to have to offset your gradient box to match the position of the ellipse.
Line 2:
mat.createGradientBox(150, 100, 0, GlobalVariables.globalStage.stageWidth / 2 - 75, -50);
Or you can also make your ellipse at 0, 0 and move the timeField to the center where you want it.
timeField.graphics.drawEllipse(0, 0, 150, 100);
timeField.x = GlobalVariables.globalStage.stageWidth / 2 - 75;
timeField.y = -50;

Html5 Canvas - Shading an outside area

I need to shade an OUTSIDE area, ie the shapes I draw in the shader are drawn normally, and their inverse is then shaded. Its easiest to explain with an example, and noting the bit that is not working:
// canvasBackground is the actual background
// canvasBackgroundContext is its context
// To make it simple, I will fill it with green
canvasBackgroundContext.fillStyle = "#00FF00";
canvasBackgroundContext.clearRect(0, 0, canvasBackground.width, canvasBackground.height);
// I also have a the shader
// canvasShader and canvasShaderContext with same width and height as canvasBackground
canvasShaderContext.fillStyle = "rgba(0, 0, 0, 0.25)"; // Black but slightly transparent
canvasShaderContext.clearRect(0, 0, canvasShader.width, canvasShader.height);
// Everything so far is great - now the problem
// This is wrong, because when I create the area I want to create clear, it does not work
// because when you draw a shape it does not work like clearRect, as it does not set each pixel to a clear pixel
canvasShaderContext.fillStyle = "rgba(0, 0, 0, 0.0)";
// Create the only non shaded bits in the shader, overlapping rects
canvasShaderContext.fillRect(10, 10, 50, 50);
canvasShaderContext.fillRect(40, 40, 50, 50);
// So when I do this, it should shade the entire background except for the two 50x50 overlapping rects at 10,10 and 40,40
canvasBackgroundContext.drawImage(canvasShaderContext, 0, 0);
I don't want to go to a pixel by pixel basis using getImageData, as that is slow. There must be some way of doing this.
I am not sure I fully understand what you try to achieve, but how about adding a composite mode to this:
canvasShaderContext.fillRect(10, 10, 50, 50);
canvasShaderContext.fillRect(40, 40, 50, 50);
which results in:
/// store old mode whatever that is
var oldMode = canvasShaderContext.globalCompositeOperation;
/// this uses any shape that is drawn next to punch a hole
/// in destination (current context).
canvasShaderContext.globalCompositeOperation = 'destination-out';
/// now draw the holes
canvasShaderContext.fillRect(10, 10, 50, 50);
canvasShaderContext.fillRect(40, 40, 50, 50);
/// set back to old mode
canvasShaderContext.globalCompositeOperation = oldMode;
That will also clear the alpha bits.

How would one make this shape in an HTML5 canvas?

I'm wonder how you would go about and create a shape similar to this one below in HTML5 Canvas. It's more or less a cropped circle I guess, though my need would render it a synch different.
http://img826.imageshack.us/img826/5198/98359410.jpg
context.fillStyle = "#000";
context.beginPath();
context.arc(200,200,100,0,Math.PI*2,true);
context.closePath();
context.fill();
Now to crop the booger, I'm perplexed. Could anyone lend me a hand? Thanks!
context.globalCompositeOperation = 'destination-in';
context.fillRect(200, 220, 200, 100); //Or something similar
destination-in means, per MDC: The existing canvas content is kept where both the new shape and existing canvas content overlap. Everything else is made transparent.
Or conversly
context.fillRect(200, 220, 200, 100);
context.globalCompositeOperation = 'source-in';
//Draw arc...
source-in means: The new shape is drawn only where both the new shape and the destination canvas overlap. Everything else is made transparent
Both these methods will end up disrupting other content already drawn to canvas, if this is an issue, use clip
context.save();
context.beginPath();
//Draw rectangular path
context.moveTo(200, 220);
context.lineTo(400, 220);
context.lineTo(400, 320);
context.lineTo(200, 320);
context.lineTo(200, 220);
//Use current path as clipping region
context.clip();
//Draw arc...
//Restore original clipping region, likely the full canvas area
context.restore()