Create soft round circles HTML5 - html

I created circles using HTML5 Canvas. I want them to look like the soft, round brushes done with Photoshop. In this code, I can only create the circles with specific opacity:
function drawClusters(ctx) {
var startPoint = (Math.PI/180)*0;
var endPoint = (Math.PI/180)*360;
ctx.beginPath();
ctx.arc(30,30,10,startPoint,endPoint,true); // x, y, r
ctx.fillStyle = "rgb(255,255,204)";
ctx.globalAlpha = 0.5;
ctx.fill();
ctx.closePath();
}
How is it possible to achieve the soft round effect? Something like the following image:

http://jsfiddle.net/pr9r7/2/ - v2, fixed overlaping issue.
function my_circle(ctx, x, y, size, color1, color2){
var color1_rgb = hex2rgb(color1);
var color2_rgb = hex2rgb(color2);
var radgrad = ctx.createRadialGradient(
x, y, size*0,
x, y, size);
radgrad.addColorStop(0, "rgba("+color1_rgb.r+", "+color1_rgb.g+", "+color1_rgb.b+", 1)");
radgrad.addColorStop(1, "rgba("+color2_rgb.r+", "+color2_rgb.g+", "+color2_rgb.b+", 0)");
ctx.fillStyle = radgrad;
ctx.fillRect(x-size,y-size,size*2,size*2);
}

This is probably not the answer (because it does not use canvas, but plain HTML and CSS), however your question made me play a little :)
http://jsfiddle.net/n5axu/
A DIV can be styled with the box-shadow css property to get similar circles.
HTML
<div class="circle white"></div>
CSS
.circle {
height: 0;
width: 0;
box-shadow: 0 0 70px 60px;
position: fixed;
}
.circle.white { color: white; }
body { background-color: black; }

Related

How do I draw <div> elements on top of a three.js canvas with a transparent background?

I was reading this answer but the approach proposed is purely theoretical. In my HTML5 code I've tried something like this:
<div id='gameCanvas'>
<div id="insideText">First trial</div>
</div>
and in the CSS I've put this:
#insideText{
background-color: transparent;
}
I'm quite a newbie when it comes to HTML/CSS, so I'm probably making some easy mistake, but this way I get a black line above my canvas, and the text appears in that black line. I want the text to appear over the canvas without this black line, and I would also like to know how to place some text on different areas of the canvas (my canvas is not fullscreen).
Edit:
If I put the <div> outside the canvas element it appears with a transparent background indeed, but always as a separate element from the canvas.
Your question isn't specific to three or canvas. It's just a basic HTML/CSS question which I'm sure is answered 1000 times on this site but since search sucks I'll answer again and leave it to someone with more patience to close as a dupe
To make 2 or more elements overlap you generally need a parent element. That element has to have css position: relative; or position:absolute;. That makes it the anchor/origin/base for its children. Note: <body> is already marked this way.
Then for all the children you can use position:absolute and set their positions with left, top, right, or bottom
Example
const ctx = document.querySelector('canvas').getContext('2d');
ctx.fillStyle = 'yellow';
ctx.fillRect(0, 0, 300, 150);
ctx.fillStyle = 'red';
ctx.arc(150, 75, 125, 0, Math.PI * 2, true);
ctx.fill();
<h1>Some text</h1>
<div style="position: relative; display: inline-block;">
<canvas></canvas>
<div style="position: absolute; left: 1em; top: 1em;">foo</div>
<div style="position: absolute; right: 1em; bottom: 1em;">bar</div>
</div>
note: the display: inline-block; is to make the outer element fit the content rather than stretch to width of its parent (the body in this case). There are 100s of other ways to set the size of elements.
note that elements are transparent by default so no need to set the background color as transparent unless you set it somewhere else as non-transparent
const renderer = new THREE.WebGLRenderer();
document.querySelector('#gameCanvas').appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.add(
new THREE.Mesh(
new THREE.SphereGeometry(1),
new THREE.MeshBasicMaterial({color:'red'})
)
);
scene.background = new THREE.Color('yellow');
const camera = new THREE.PerspectiveCamera(45, 2, .1, 10);
camera.position.z = 2;
renderer.render(scene, camera);
#gameCanvas {
position: relative;
}
#insideText {
position: absolute;
left: 20px;
top: 20px;
}
<h1>some text</h1>
<div id='gameCanvas'>
<div id="insideText">First trial</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.min.js"></script>

Crop image into square and then to circle using pure CSS?

I'm trying to make a circle out of images with different sizes and different shapes (some rectangle, some sqaure, some portrait, some landscape).
When I'm using: clip-path: circle(50% at 50% 50%); or border-radius: 50%;, it turns the image into a perfect circle, only if the image is square:
Is there a way to crop an image into a square and then use one of these methods to make it a perfect circle:
Using pure CSS withou using background-image (most images are given the background image from server side),
Keeping a 50% ratio - without losing aspect ratio - (both if border-radius or clip-path)(Images size may vary).
Here's a code snippet to show a square image and a rectangle image:
.clipped {
clip-path: circle(50% at 50% 50%);
}
Square<br>
<img src='http://i.imgur.com/d5byNNR.jpg' width="100" class='clipped' /><br><br>
Rectangle<br>
<img src='http://i.imgur.com/22W12EQ.jpg' width="100" class='clipped' />
You can use circle() but without the parameters:
.clipped {
clip-path: circle();
}
It appears to use the smaller side of your image as the circle's circumference.
Working sample here.
It works on Chrome and FireFox. IE and Edge still does not support clip-path
That's an another way to do it using pure CSS:
HTML
<div class="circular--portrait">
<img src='http://i.imgur.com/22W12EQ.jpg'/>
</div>
CSS
.circular--portrait {
position: relative;
overflow: hidden;
width: 100px;
height: 100px;
border-radius: 50%;
}
.circular--portrait img {
width: 100%;
height: auto;
margin-top: -30px;
}
Code Snippet (with portrait and landscape examples)
Alright, took me a moment but this is what I came up with:
function ScaleImage(srcwidth, srcheight, targetwidth, targetheight, fLetterBox, xOffSet, yOffSet) {
var result = { width: 0, height: 0, fScaleToTargetWidth: true };
if ((srcwidth <= 0) || (srcheight <= 0) || (targetwidth <= 0) || (targetheight <= 0)) {
return result;
}
// scale to the target width
var scaleX1 = targetwidth;
var scaleY1 = (srcheight * targetwidth) / srcwidth;
// scale to the target height
var scaleX2 = (srcwidth * targetheight) / srcheight;
var scaleY2 = targetheight;
// now figure out which one we should use
var fScaleOnWidth = (scaleX2 > targetwidth);
if (fScaleOnWidth) {
fScaleOnWidth = fLetterBox;
}
else {
fScaleOnWidth = !fLetterBox;
}
if (fScaleOnWidth) {
result.width = Math.floor(scaleX1);
result.height = Math.floor(scaleY1);
result.fScaleToTargetWidth = true;
}
else {
result.width = Math.floor(scaleX2);
result.height = Math.floor(scaleY2);
result.fScaleToTargetWidth = false;
}
//result.targetleft = Math.floor((targetwidth - result.width) / 2);
//result.targettop = Math.floor((targetheight - result.height) / 2);
result.targetleft = Math.floor((targetwidth - result.width) / 2 - xOffSet);
result.targettop = Math.floor((targetheight - result.height) / 2 - yOffSet);
return result;
}
function OnImageLoad(evt, xOffSet = 0, yOffSet = 0) {
var img = evt.currentTarget;
// what's the size of this image and it's parent
var w = $(img).width();
var h = $(img).height();
var tw = $(img).parent().width();
var th = $(img).parent().height();
// compute the new size and offsets
var result = ScaleImage(w, h, tw, th, false, xOffSet, yOffSet);
// adjust the image coordinates and size
img.width = result.width;
img.height = result.height;
$(img).css("left", result.targetleft);
$(img).css("top", result.targettop);
}
.result {
width: 250px;
height: 250px;
border: thick solid #666666;
overflow: hidden;
position: relative;
border-radius: 50%;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
No offset:
<div class='result'>
<img src="http://i.imgur.com/22W12EQ.jpg" style="position: absolute;" onload="OnImageLoad(event, 0, 0);"/>
</div>
Y offset:
<div class='result'>
<img src="http://i.imgur.com/22W12EQ.jpg" style="position: absolute;" onload="OnImageLoad(event, 0, 30);"/>
</div>
I took most of the work from this resource: https://selbie.wordpress.com/2011/01/23/scale-crop-and-center-an-image-with-correct-aspect-ratio-in-html-and-javascript/ and I've adepted it to allow the use of Offsets so you can crop any image at the position you want.
How it works
You create a div of any size you want. It can be square, but if you want an egg-like result, that works as well (lol). Then insert the image of any unknown size inside it.
Change onload="OnImageLoad(event, 0, 30); with the offsets you want. Positive offsets for moving the image left or down, negative for up or right.
Note: I did use jQuery for this.

Random cutouts with HTML5 Canvas

All I'm trying to do is to get random cutouts (different shapes) via HTML Canvas element.
On the page I have a DIV, and above it I have the canvas element. So far I was able to color the element and cut out the first piece (not random), and wipe/clean the canvas again, but when I'm trying to do the exact same thing multiple times, it wouldn't work :/
Here is the half-working example: http://plnkr.co/edit/a5UAutd2jNgHMTtPMsp4
var cutThatOut = function(coords) {
ctx.fillStyle = "rgba(0,0,0,1)";
ctx.globalCompositeOperation = "destination-out";
coords.forEach(function(coord, i){
if (i==0) {
ctx.moveTo(coord.x, coord.y);
} else {
ctx.lineTo(coord.x, coord.y);
}
});
ctx.fill();
}
thanks for your time/help
Several fixes:
Start your new set of path commands with ctx.beginPath. Otherwise your previous sets of drawing commands will be repeated along with the newest set.
Make sure you reset compositing at the end of cutThatOut. Otherwise your next fillRect(0,0,c.width,c.height) will "erase" the whole canvas because it's still using 'destination-out'.
If you want to do a completely new cutout with each call to cutThatOut then refill the canvas with black at the start of cutThatOut
Just a note: Your random coordinates often cause intersecting sides of the polygon and often extend outside the boundaries of the canvas.
Here's example code and a Demo:
var c = document.getElementById("canvas");
var ctx = c.getContext('2d');
var cutThatOut = function(coords) {
ctx.fillStyle = "black";
ctx.fillRect(0,0,c.width, c.height);
ctx.fillStyle = "rgba(0,0,0,1)";
ctx.globalCompositeOperation = "destination-out";
ctx.beginPath();
coords.forEach(function(coord, i){
if (i==0) {
ctx.moveTo(coord.x, coord.y);
} else {
ctx.lineTo(coord.x, coord.y);
}
});
ctx.fill();
ctx.globalCompositeOperation = "source-over";
}
var wipeIt = function() {
ctx.clearRect(0,0,c.width,c.height);
}
var getRand = function(min, max) {return Math.round(Math.random() * (max - min) + min);}
cutThatOut([
{x:c.width/2, y:0},
{x:c.width,y:c.height/2},
{x:c.width/2,y:c.height},
{x:0, y:c.height/2}
]);
$("#btn").on("click", function(){
wipeIt();
cutThatOut([
{x:getRand(1,200), y:getRand(1,200)},
{x:getRand(1,200), y:getRand(1,200)},
{x:getRand(1,200), y:getRand(1,200)},
{x:getRand(1,200), y:getRand(1,200)}
]);
});
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
.adiv {
width: 200px;
height: 200px;
background-color: yellow;
position: relative;
}
#canvas {
width: 200px;
height: 200px;
position:absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="adiv">
<canvas id="canvas"></canvas>
</div>
<p>
<button id="btn">NEXT!</button>
</p>

Canvas not working as intended

I was trying a script to draw graph paper like grids on the canvas from dive into html5. The result is supposed to draw a mesh with squares of side 10px but i'm getting the size as approximately 20px, and not exact squares.
Here is the code,`
<html>
<head>
<style>
body{
margin: 20px 20px 20px 20px;
}
canvas{
width: 500px;
height: 375px;
border: 1px solid #000;
}
</style>
<script type="text/javascript">
function activate(){
var canvas =document.getElementById("exp");
var context = canvas.getContext("2d");
for (var x=0.5;x<500;x+=10){
context.moveTo(x,0);
context.lineTo(x,375);
console.log(x);
}
for (var y=0.5;y<375;y+=10){
context.moveTo(0,y);
context.lineTo(500,y);
}
context.strokeStyle="#000";
context.stroke();
}
</script>
</head>
<body>
<canvas id="exp"><script type="text/javascript">activate();</script></canvas>
</body
</html>
And this is the output:
while the actual output should be:
Note: i'm not worried about the color difference. what i don't understand is why the space between 2 lines is ~20px(as checked by a measurement tool on firefox) instead of 10px.
Also, on printing the values of x, it gives the right value(i.e. incremented by 10 each time).
you can not set the canvas' size with css
you should set in the DOM's attribute.
<canvas width="100" height="200"></canvas>
Javascript can calculate for you. Only set the parameters:
html:
<canvas id="exp"></canvas>
js:
function activate(id, xcount, ycount, width, color) {
var canvas = document.getElementById(id);
var context = canvas.getContext("2d");
canvas.width = xcount * width + 1;
canvas.height = ycount * width + 1;
for (var x = 0.5; x < canvas.width; x += width) {
context.moveTo(x, 0);
context.lineTo(x, canvas.height);
}
for (var y = 0.5; y < canvas.height; y += width) {
context.moveTo(0, y);
context.lineTo(canvas.width, y);
}
context.strokeStyle = color;
context.stroke();
}
activate("exp", 37, 50, 10, "#ccc");
Also see this example.

Equivalent of canvas "destination-out" for normal html element?

I've searched around quite a bit and I'm fairly certain this doesn't exist, I'm mainly looking to confirm that. What I'd like to do is have a div that makes everything behind it transparent -- similar to what canvas' destination-out compositing option does.
For a little more context, here's the situation. I have an OpenGL window drawing behind a QtWebKit overlay. The OpenGL window has multiple "subwindows" that can be overlapping, which are decorated using the WebKit overlay. When they overlap though, because of this two layer system, the decorations for the overlapped windows do not get occluded.
The backup option is just to use a full-window canvas for this (the window trimmings are fairly simple), but it would be nicer not to. Note that because this is an embedded WebKit instance, it doesn't need to be cross-browser, and something WebKit (or QtWebKit) specific is fine.
EDIT
I can't answer my own question within 24 hours, so here's my solution, with thanks to #Kevin Peno
The following is a simplified version of what I was looking for. It creates two divs "visible" and "invisible". "invisible" masks off "visible" so that it displays the background image behind it instead of the "visible" div.
The real keys are -webkit-mask-image (http://www.webkit.org/blog/181/css-masks/) and -webkit-canvas (http://www.webkit.org/blog/176/css-canvas-drawing/), so this will only work with webkit-based browsers.
HTML:
<html>
<body>
<div id="visible"/>
<div id="invisible"/>
</body>
</html>
JavaScript:
function updateMask()
{
var w = $("#visible").width();
var h = $("#visible").height();
var context = document.getCSSCanvasContext("2d", "mask", w, h);
context.fillStyle = "rgba(255, 255, 255, 1.0)";
context.fillRect(0, 0, w, h);
var my_off = $("#visible").offset();
var inv_off = $("#invisible").offset();
var rel_left = inv_off.left - my_off.left;
var rel_top = inv_off.top - my_off.top;
context.clearRect(rel_left, rel_top, $("#invisible").width(), $("#invisible").height());
}
$(window).ready(function()
{
updateMask();
$("#invisible").draggable();
$("#invisible").bind("drag", function(e, ui)
{
console.log("drag");
updateMask();
e.preventDefault();
});
});
CSS:
body
{
background-image: url(http://www.google.com/images/logos/ps_logo2.png);
}
#visible
{
position: absolute;
background-color: red;
z-index: 0;
width: 1000px;
height: 1000px;
top: 0;
left: 0;
-webkit-mask-image: -webkit-canvas(mask);
}
#invisible
{
position: absolute;
z-index: 1;
width: 100px;
height: 100px;
top: 50px;
left: 50px;
cursor: move;
background-color: rgba(0, 255, 0, 0.5);
}
Here's a blog post about using css to apply an image mask to an element. It sounds pretty close to what you are looking for or will at least be good for some ideas. Let me know how it works out.
CSS Masks