I have a requirement to fill a shape with a two colours - like a chess board.
I have seen some gradient effects with css but have not seen any examples like this.
Would this even be possible in Html5 Canvas?
You sure can. In fact you can fill any arbitrary shape with any repeatable thing, even with shapes that you make in the Canvas itself!
Here's an example of an arbitrary shape getting filled with "pea pods" that were defined on a canvas: http://jsfiddle.net/NdUcv/
Here it is with a simple checkerboard pattern: http://jsfiddle.net/NdUcv/2/
That second one makes a shape fill look like this:
I create that pattern by making a canvas and then drawing whatever I want to repeat on it:
var pattern = document.createElement('canvas');
pattern.width = 40;
pattern.height = 40;
var pctx = pattern.getContext('2d');
// Two green rects make a checkered square: two green, two transparent (white)
pctx.fillStyle = "rgb(188, 222, 178)";
pctx.fillRect(0,0,20,20);
pctx.fillRect(20,20,20,20);
Then on my normal canvas I can do:
var pattern = ctx.createPattern(pattern, "repeat");
ctx.fillStyle = pattern;
and draw fill anything with that pattern.
Of course it doesn't have to be a canvas path, you could use a checkerboard image (or any kind of image) and fill a shape with it using the canvas patterns.
I did a quick example
<html>
<head>
<hea>
<body onload='xx()'>
<canvas id='mycanvas' width='256' height='256'>ops</canvas>
</body>
<script type='text/javascript'>
function xx(){
var canvas= document.getElementById('mycanvas');
ctx= canvas.getContext('2d');
for(var i=0;i<8;i++){
for(var j=0;j<8;j++){
if (ctx.fillStyle == '#000000')
ctx.fillStyle = 'blue';
else ctx.fillStyle = '#000000';
ctx.fillRect(32*j, 32*i, 32,32);
}
if (ctx.fillStyle == '#000000')
ctx.fillStyle = 'blue';
else ctx.fillStyle = '#000000';
}
}
Related
I am currently rendering a canvas below some HTML elements (currently a h1 and a span). The canvas contains a kaleidoscope based on an image with two major colors: one pretty dark (almost black), and one really bright, and it can be moved by moving the mouse. The HTML elements are rendered with a color: white style.
The problem I encounter is when the kaleidoscope renders a huge white part. The text becomes invisible. Is it possible to make the text display the negative color of the part of the canvas right under it ? So for example, if the part of the canvas under the text is white, the text would be black ? Here is a screenshot of the problem:
You can set the color to white and use css blending-mode difference:
h1{
color:white;
mix-blend-mode: difference;
}
Demo
Sure, you can use the "difference" blending mode to make the text change color:
ctx.globalCompositeOperation = "difference";
ctx.fillText(myText, x, y);
Example
var ctx = c.getContext("2d");
var toggle = false;
for(var x = 0, step = c.width / 16; x < c.width; x += step) {
toggle = !toggle;
ctx.fillStyle = toggle ? "#000" : "#fff";
ctx.fillRect(x, 0, step, c.height);
}
ctx.globalCompositeOperation = "difference";
ctx.font = "32px sans-serif";
ctx.textAlign = "center";
ctx.fillText("ALTERNATING", c.width>>1, c.height>>1);
<canvas id=c></canvas>
Creative options: draw background slightly transparent to make white light-grey (setting the canvas element's CSS opacity), use shadow or outline for the text.
I have a canvas which is currently drawing a grey scale diagram (JSBin example).
It's effectively a radial progress meter, that will be used a lot in the application. However, rather than colouring it with Javascript, I'd prefer to be able to give it a colour based on a class.
I thought it would be an ideal use case for CSS filters. I'd draw the default progress meter in gray, then use CSS filters to add saturation and do a hue rotation, in order to achieve blue, orange and green too.
canvas {
-webkit-filter: saturate(8);
}
The rule was supported and valid in Chrome, but the problem was, it doesn't seem to change the saturation at all.
I'm imagining that #aaa is transformed into it's HSL counterpart hsl(0, 0%, 67%). Then when I increase the saturation with a filter, it should become more saturated, but for the same hue.
I was hoping to end up with something like hsl(0, 50%, 67%) but instead, the filter doesn't seem to change the colour at all, no matter what value I use.
Any ideas?
It turns out if you draw the meter with some saturation initially, you can use the hue-rotate filter and then you can desaturate them to achieve grey scale again.
http://jsbin.com/qohokivobo/2/edit?html,css,output
Conceptually, this isn't an answer. But in the meantime, it's a solution.
What about picking the color from the CSS style ?
canvas {
color: red;
}
function init() {
let canvas = document.getElementById('test'),
context = canvas.getContext('2d');
let style = window.getComputedStyle (canvas);
let color = style.color;
canvas.width = 300;
canvas.height = 300;
let x = canvas.width / 2,
y = canvas.height / 2;
context.beginPath( );
context.arc(x, y, 100, 0, 2 * Math.PI, false);
context.strokeStyle = color;
context.lineWidth = 20;
context.stroke();
context.globalAlpha = 0.85;
context.beginPath();
context.arc(x, y, 100, 0, Math.PI + 0.3, false);
context.strokeStyle = '#eee';
context.stroke();
}
demo
I'm trying to draw an image on a canvas, then use css to fit the canvas within a certain size. It turns out that many browsers don't scale the canvas down very nicely. Firefox on OS X seems to be one of the worst, but I haven't tested very many. Here is a minimal example of the problem:
HTML
<img>
<canvas></canvas>
CSS
img, canvas {
width: 125px;
}
JS
var image = document.getElementsByTagName('img')[0],
canvas = document.getElementsByTagName('canvas')[0];
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
image.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Helvetica_Neue_typeface_weights.svg/783px-Helvetica_Neue_typeface_weights.svg.png"
Running in a codepen: http://codepen.io/ford/pen/GgMzJd
Here's the result in Firefox (screenshot from a retina display):
What's happening is that both the <img> and <canvas> start at the same size and are scaled down by the browser with css (the image width is 783px). Apparently, the browser does some nice smoothing/interpolation on the <img>, but not on the <canvas>.
I've tried:
image-rendering, but the defaults seem to already be what I want.
Hacky solutions like scaling the image down in steps, but this didn't help: http://codepen.io/ford/pen/emGxrd.
Context2D.imageSmoothingEnabled, but once again, the defaults describe what I want.
How can I make the image on the right look like the image on the left? Preferably in as little code as possible (I'd rather not implement bicubic interpolation myself, for example).
You can fix the pixelation issue by scaling the canvas's backing store by the window.devicePixelRatio value. Unfortunately, the shoddy image filtering seems to be a browser limitation at this time, and the only reliable fix is to roll your own.
Replace your current onload with:
image.onload = function() {
var dpr = window.devicePixelRatio;
canvas.width = image.width * dpr;
canvas.height = image.height * dpr;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
Results:
Tested on Firefox 35.0.1 on Windows 8.1. Note that your current code doesn't handle browser zoom events, which could reintroduce pixelation. You can fix this by handling the resize event.
Canvas is not quite meant to be css zoomed : Try over-sampling : use twice the required canvas size, and css scaling will do a fine job in down-scaling the canvas.
On hi-dpi devices you should double yet another time the resolution to reach the
same quality.
(even on a standard display, X4 shines a bit more).
(Image, canvas 1X, 2X and 4X)
var $ = document.getElementById.bind(document);
var image = $('fntimg');
image.onload = function() {
drawAllImages();
}
image.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Helvetica_Neue_typeface_weights.svg/783px-Helvetica_Neue_typeface_weights.svg.png"
function drawAllImages() {
drawImage(1);
drawImage(2);
drawImage(4);
}
function drawImage(x) {
console.log('cv' + x + 'X');
var canvas = $('cv' + x + 'X');
canvas.width = x * image.width;
canvas.height = x * image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
img,
canvas {
width: 125px;
}
<br>
<img id='fntimg'>
<canvas id='cv1X'></canvas>
<canvas id='cv2X'></canvas>
<canvas id='cv4X'></canvas>
<br>
It's not good idea to scale canvas and think that you solved the image scale problem.you can pass your dynamic value to canvas,and then draw with that size whatever you want.
here is link of canvas doc: http://www.w3docs.com/learn-javascript/canvas.html
Simple answer, you can't do it. The canvas is just like a bitmap, nothing more.
My idea:
You should redraw the whole surface on zooming, and make sure you scale the image you're drawing to the canvas. As it is a vector graphic, this should work. But you're going to have to redraw the canvas for sure.
I have this function that basically adds a given text below a given image, I wish to make the corners of textRect round, can you help me understand how to use UIBezierPath in this code
-(UIImage*) overlapText:(NSString*) p_text inImage:(UIImage*) p_image atPoint:(CGPoint) p_point
{
p_point.y += p_image.size.height-5;
UIFont *font = [UIFont boldSystemFontOfSize:11];
UIGraphicsBeginImageContext(CGSizeMake(p_image.size.width+15,p_image.size.height+15));
CGFloat imageX = (p_image.size.width+10)/2 - (p_image.size.width/2);
[p_image drawInRect:CGRectMake(imageX,0,p_image.size.width,p_image.size.height)];
CGRect textRect = CGRectMake(0, p_point.y, p_image.size.width+15, p_image.size.height+10);
[[UIColor colorWithRed:(70/255.0) green:(70/255.0) blue:(70/255.0) alpha:1] set];
CGContextFillRect(UIGraphicsGetCurrentContext(), textRect);
[[UIColor whiteColor] set];
[p_text drawInRect:textRect withFont:font lineBreakMode:NSLineBreakByTruncatingTail alignment:NSTextAlignmentCenter];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Your image context is the current context, so just construct the rounded rect with bezierPathWithRoundedRect:cornerRadius:, set your fill color, and tell the bezier path to fill. It's one line of code (well, two if you count setting the fill color):
[[UIColor colorWithRed:(70/255.0) green:(70/255.0) blue:(70/255.0) alpha:1] set];
[[UIBezierPath bezierPathWithRoundedRect:textRect cornerRadius:5] fill];
Feel free to play with the numbers here; for example, you might like a different corner radius. Experiment!
Recently I started working on HTML5 Canvas, I'm new to it.
I've a problem as follows:
I'm loading a Canvas with Body Chart Image (Predefined Image) and on that User will Draw some lines, shapes, etc.
After that I'll generate an image object as follows
var canvas = document.getElementById("MyCanvas");
var dataURL = canvas.toDataURL();
var image = new Image();
image.src = dataURL;
But, Here it generates only those elements which are drawn by users (lines, shapes) as PNG Image. It won't take that Predefined canvas background Image.
I need to generate a PNG image which should include both the Canvas background Image as well as User entered drawing elements.
How to do this?
Try to actually draw you image onto your canvas, utilizing these functions:
var canvas = document.getElementById("MyCanvas");
var img = new Image();
img.src = 'pathToYourImageHere';
canvas.drawImage(img,0,0); /* 0,0 is x and y from the top left */
When you now try to save it, it should also save your background image.
EDIT:
In response to your comment:
You can circument your layering problem by using two different canvases. One for the image, and one for your drawing. Then layer them on top of each other using absolute positioning.
You can read more here: Save many canvas element as image
EDIT2:
But actually you shouldn't have a layering problem, since the following code will first draw the image and then draw the arc, and the layering will be fine:
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.src = "somePathToAnImage";
context.drawImage(imageObj, 50, 50);
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 1.1 * Math.PI;
var endAngle = 1.9 * Math.PI;
var counterClockwise = false;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.lineWidth = 15;
// line color
context.strokeStyle = "red";
context.stroke();
Even though the layering is fine, you will be better of by using two canvases, in case you would like to only save the drawing, without the background. You can always save both into a new canvas and save that, when you only use one canvas you'll have a hard time separating the drawing from the background.
This is because the image needs time to load, you have to use the onload function.
imgObj.onload = function() { context.drawImage(imageObj, 50, 50); imgLoaded = true;}
if (imgLoaded) { /*you draw shapes here */ }