I found a post a while back were someone made a corner blob animation similar to the one on the old discord login page (jsfiddle). I want to move it to the right side of the page. I don't know exactly how it works.
const SCALE = 0.25;
const TWO_PI = Math.PI * 2;
const HALF_PI = Math.PI / 2;
const canvas = document.createElement("canvas");
const c = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
class Blob {
constructor() {
this.wobbleIncrement = 0;
// use this to change the size of the blob
this.radius = 500;
// think of this as detail level
// number of conections in the `bezierSkin`
this.segments = 12;
this.step = HALF_PI / this.segments;
this.anchors = [];
this.radii = [];
this.thetaOff = [];
const bumpRadius = 100;
const halfBumpRadius = bumpRadius / 2;
for (let i = 0; i < this.segments + 2; i++) {
this.anchors.push(0, 0);
this.radii.push(Math.random() * bumpRadius - halfBumpRadius);
this.thetaOff.push(Math.random() * TWO_PI);
}
this.theta = 0;
this.thetaRamp = 0;
this.thetaRampDest = 12;
this.rampDamp = 25;
}
update() {
this.thetaRamp += (this.thetaRampDest - this.thetaRamp) / this.rampDamp;
this.theta += 0.03;
this.anchors = [0, this.radius];
for (let i = 0; i <= this.segments + 2; i++) {
const sine = Math.sin(this.thetaOff[i] + this.theta + this.thetaRamp);
const rad = this.radius + this.radii[i] * sine;
const theta = this.step * i;
const x = rad * Math.sin(theta);
const y = rad * Math.cos(theta);
this.anchors.push(x, y);
}
c.save();
c.translate(-10, -10);
c.scale(SCALE, SCALE);
c.fillStyle = "blue";
c.beginPath();
c.moveTo(0, 0);
bezierSkin(this.anchors, false);
c.lineTo(0, 0);
c.fill();
c.restore();
}
}
const blob = new Blob();
function loop() {
c.clearRect(0, 0, canvas.width, canvas.height);
blob.update();
window.requestAnimationFrame(loop);
}
loop();
// array of xy coords, closed boolean
function bezierSkin(bez, closed = true) {
const avg = calcAvgs(bez);
const leng = bez.length;
if (closed) {
c.moveTo(avg[0], avg[1]);
for (let i = 2; i < leng; i += 2) {
let n = i + 1;
c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]);
}
c.quadraticCurveTo(bez[0], bez[1], avg[0], avg[1]);
} else {
c.moveTo(bez[0], bez[1]);
c.lineTo(avg[0], avg[1]);
for (let i = 2; i < leng - 2; i += 2) {
let n = i + 1;
c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]);
}
c.lineTo(bez[leng - 2], bez[leng - 1]);
}
}
// create anchor points by averaging the control points
function calcAvgs(p) {
const avg = [];
const leng = p.length;
let prev;
for (let i = 2; i < leng; i++) {
prev = i - 2;
avg.push((p[prev] + p[i]) / 2);
}
// close
avg.push((p[0] + p[leng - 2]) / 2, (p[1] + p[leng - 1]) / 2);
return avg;
}
I hope these 2 changes in update function help you:
c.translate(canvas.width-10, -10);
c.rotate(Math.PI / 2)
Full Code:
const SCALE = 0.25;
const TWO_PI = Math.PI * 2;
const HALF_PI = Math.PI / 2;
const canvas = document.createElement("canvas");
const c = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
class Blob {
constructor() {
this.wobbleIncrement = 0;
// use this to change the size of the blob
this.radius = 500;
// think of this as detail level
// number of conections in the `bezierSkin`
this.segments = 12;
this.step = HALF_PI / this.segments;
this.anchors = [];
this.radii = [];
this.thetaOff = [];
const bumpRadius = 100;
const halfBumpRadius = bumpRadius / 2;
for (let i = 0; i < this.segments + 2; i++) {
this.anchors.push(0, 0);
this.radii.push(Math.random() * bumpRadius - halfBumpRadius);
this.thetaOff.push(Math.random() * TWO_PI);
}
this.theta = 0;
this.thetaRamp = 0;
this.thetaRampDest = 12;
this.rampDamp = 25;
}
update() {
this.thetaRamp += (this.thetaRampDest - this.thetaRamp) / this.rampDamp;
this.theta += 0.03;
this.anchors = [0, this.radius];
for (let i = 0; i <= this.segments + 2; i++) {
const sine = Math.sin(this.thetaOff[i] + this.theta + this.thetaRamp);
const rad = this.radius + this.radii[i] * sine;
const theta = this.step * i;
const x = rad * Math.sin(theta);
const y = rad * Math.cos(theta);
this.anchors.push(x, y);
}
c.save();
c.translate(canvas.width-10, -10);
c.rotate(Math.PI / 2)
c.scale(SCALE, SCALE);
c.fillStyle = "blue";
c.beginPath();
c.moveTo(0, 0);
bezierSkin(this.anchors, false);
c.lineTo(0, 0);
c.fill();
c.restore();
}
}
const blob = new Blob();
function loop() {
c.clearRect(0, 0, canvas.width, canvas.height);
blob.update();
window.requestAnimationFrame(loop);
}
loop();
// array of xy coords, closed boolean
function bezierSkin(bez, closed = true) {
const avg = calcAvgs(bez);
const leng = bez.length;
if (closed) {
c.moveTo(avg[0], avg[1]);
for (let i = 2; i < leng; i += 2) {
let n = i + 1;
c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]);
}
c.quadraticCurveTo(bez[0], bez[1], avg[0], avg[1]);
} else {
c.moveTo(bez[0], bez[1]);
c.lineTo(avg[0], avg[1]);
for (let i = 2; i < leng - 2; i += 2) {
let n = i + 1;
c.quadraticCurveTo(bez[i], bez[n], avg[i], avg[n]);
}
c.lineTo(bez[leng - 2], bez[leng - 1]);
}
}
// create anchor points by averaging the control points
function calcAvgs(p) {
const avg = [];
const leng = p.length;
let prev;
for (let i = 2; i < leng; i++) {
prev = i - 2;
avg.push((p[prev] + p[i]) / 2);
}
// close
avg.push((p[0] + p[leng - 2]) / 2, (p[1] + p[leng - 1]) / 2);
return avg;
}
Related
i am using electron(nodejs framework ) and i want to render crispy text for convert it into bitmap and show it on led brick.
like led show software please help.
my code is working but it's system dependent it working fine in some computer but to blurry in some computer.
calling parameter in main.js.
let height = 96;
let width = 288;
let letterSpacing = 1;
var font = "Arial";
var fontSize = 11;
let text_x = 1;
let text_y = 1;
const canvas = new Canvas(height, width, letterSpacing, font, fontSize, text_x, text_y);
here is my canvas.js file.
class Canvas {
constructor(height, width, latterSpacing = 1, font, fontSize, text_x, text_y) {
this.width = width;
this.height = height;
this.letterSpacing = latterSpacing;
this.font = font;
this.fontSize = fontSize;
this.text_x = text_x;
this.text_y = text_y;
this.maxWidth = 32;
this.offset = 0.5;
this.canvas = document.getElementById("myCanvas");
this.ctx = this.canvas.getContext("2d");
}
PIXEL_RATIO = (function () {
// var ctx = document.createElement("canvas").getContext("2d"),
var ctx = document.getElementById("myCanvas").getContext("2d"),
// var ctx = this.ctx,
dpr = window.devicePixelRatio || 1,
bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;
return dpr / bsr;
})();
setwidth(maxwidth) {
this.maxWidth = maxwidth;
// this.offset = ofset;
}
setoffset(ofset) {
// this.maxWidth = maxwidth;
this.offset = ofset;
}
createHiDPICanvas = function (w, h, ratio) {
if (!ratio) { ratio = this.PIXEL_RATIO; }
// var can = document.createElement("canvas");
var can = this.canvas;
can.width = w * ratio;
can.height = h * ratio;
can.style.width = w + "px";
can.style.height = h + "px";
can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
return can;
}
createCanvas() {
try {
const canvas = document.getElementById("myCanvas");
this.canvas.retinaResolutionEnabled = false;
// this.canvas.style.letterSpacing = "1px";
this.canvas.height = this.height;
this.canvas.width = this.width;
this.canvas.style.letterSpacing = `${this.letterSpacing}px`
/*word spacing*/
// var can = this.createHiDPICanvas(this.width, this.height, 4)
// this.ctx = can.getContext("2d")
this.ctx.beginPath();
// this.ctx = this.canvas.getContext("2d");
this.ctx.fillStyle = "#FF0000";
this.ctx.font = `${this.fontSize}px ` + this.font;
/*Font style and size*/
this.ctx.strokeStyle = "#FF0000";
this.ctx.textBaseline = "top";
this.ctx.textAlign = 'start';
this.ctx.shadowOffsetX = 0;
this.canvas.retinaResolutionEnabled = false;
// this.ctx.fillText("WELCOME TO TICO", 10, 20);
return true;
} catch (error) {
return false;
}
}
clrCanvas(ix = 0, iy = 0, ex = this.canvas.width, ey = this.canvas.height) {
this.ctx.clearRect(ix, iy, ex, ey);
}
fillTextCanvas(str, row = 0, col = 0, vac = 0, hac = 1, _fontSize = this.fontSize, _font = this.font)
{
this.ctx.font = `${_fontSize}px ` + _font;
if (vac) {
col = ((this.canvas.height - (str.length * _fontSize)) / 2) + 1;
}
if (hac) {
this.ctx.textAlign = "center";
row = this.width / 2;
}
for (let index = 0; index < str.length; index++) {
// const element = array[index];
let y = (_fontSize * index) + col;
// this.ctx.fillText(str[index], width / 2, y);
/*text,x,y*/
this.ctx.fillText(str[index], row - 0.8, y - 0.8);
/*text,x,y*/
// this.ctx.fillText("hello", width/2, y);
/*text,x,y*/
}
// display_hex["Screen2"] = jsonArr;
// fillMatrix(jsonArr);
}
async getBitmap() {
var jsonArr = {};
var bin = '';
for (var j = 0; j < this.canvas.width; j++) {
bin = ""
for (var i = 0; i <= this.canvas.height; i++) {
var data = this.ctx.getImageData(j, i, 1, 1); /*getPixel,x,y*/
if (!(i % 32) && i) {
// jsonArr[j + (width * (Math.floor(i / 32) - 1))] = ("0x" + (("00000000" +
ConvertBase.bin2hex(bin)).substr(-8)));
jsonArr[j + (this.width * (Math.floor(i / 32) - 1))] =
parseInt(ConvertBase.bin2dec(bin));
bin = "";
}
if (data['data'][0] >= 200 && data['data'][3] >= 90) {
bin += "1";
} else {
bin += "0";
}
}
}
return jsonArr;
}
fillCanvas(_char, row, col, _fontSize = 11, _font = "Arial") {
this.clrCanvas();
this.ctx.font = `${_fontSize}px ` + _font;
this.ctx.textAlign = "start";
this.ctx.imageSmoothingEnabled = false;
// let linesPos = [[0, 45, 80, 119, 157, 196, 235], [1, 24, 36, 48, 60, 72, 84]]
// let linesPos = [[0, 49, 81, 119, 157, 196, 235], [1, 22, 33, 44, 55, 66, 77]]
let linesPos = [[0, 60, 98, 135, 174, 213, 252], [1, 23, 34, 45, 56, 67, 78]]
this.findColPos(_char);
// console.log(_char)
for (let _row = row; _row < _char.length; _row++) {
// let y = parseInt(text_y) + ((parseInt(fontSize) + 2) * _row);
let y = parseInt(this.text_y + 1) + ((parseInt(_fontSize)) * _row);
for (let index = col; index < _char[_row].length; index++) {
let x = parseInt(this.text_x) + linesPos[0][index];
console.log(this.ctx.measureText(_char[_row][index]).width)
// this.ctx.fillText(_char[_row][index], x + 1.8, y + 0.8,32);
/*text,x,y*/
this.ctx.fillText(_char[_row][index], x + this.offset, y + this.offset, this.maxWidth);
/*text,x,y*/
this.ctx.moveTo(0, linesPos[1][index + 1] + 0.5);
this.ctx.lineTo(this.canvas.width, linesPos[1][index + 1] + 0.5);
this.ctx.moveTo(linesPos[0][index] + 0.5, 0);
this.ctx.lineTo(linesPos[0][index] + 0.5, this.canvas.height);
}
}
this.ctx.stroke();
this.ctx.strokeRect(0, 0, this.canvas.width, this.canvas.height);
// display_hex["Screen1"] = jsonArr;
// canvasImg["Screen1"] = ($('#myCanvas')[0]).toDataURL("image/png");
// fillMatrix(jsonArr);
// return jsonArr;
}
findColPos(__char) {
let maxRow = []
maxRow[0] = 0;
let splitData = [];
maxRow[0] = [];
maxRow[1] = [];
for (let pos = 0; pos < __char[0].length; pos++) {
if (__char[0][pos].split(" ")[1]) {
splitData.push(__char[0][pos].split(" ")[1]);
} else {
// __char[0][pos] = "";
splitData[pos] = " "
}
__char[0][pos] = __char[0][pos].trim().split(" ")[0]; //_char[0][pos] _char[0].splice[];
// _char[0][pos] = splitData[0];
// _char[0].splice
// console.log(_char[0][pos].split(" ")[0]); //_char[0][pos] _char[0].splice[];
}
console.log(__char)
__char.splice(1, 0, splitData)
console.log(__char)
for (let row = 0; row < __char.length; row++) {
for (let col = 0; col < __char[row].length; col++) {
let width = this.ctx.measureText(__char[row][col]).width + 3;
if (!maxRow[0][col + 1]) {
maxRow[0][col + 1] = 0;
}
maxRow[0][col + 1] = maxRow[0][col + 1] < width ? width : maxRow[0][col + 1];
}
}
// console.log(maxRow)
for (let i = 1; i < maxRow.length; i++) {
maxRow[0][i] = maxRow[0][i] + maxRow[0][i - 1];
}
/* for (let index = 0; index < _char.length; index++) {
// const element = array[index];
maxRow[index] = ctx.measureText(_char[index]).width;
} */
// _char = __char
return maxRow;
}
createFonts(start, end) {
let arr = [];
// clearEvents();
for (let index = "/".charCodeAt(0); index <= ":".charCodeAt(0); index++) {
// const element = array[index];
// fillCanvas(index);
let txt = String.fromCharCode(index);
fillTextCanvas(txt, 0, 0, 1, 0, 32);
createCanvas(32, this.ctx.measureText(txt).width, 32);
this.ctx.textBaseline = "middle";
// fillTextCanvas(txt, text_x, text_y);
this.clrCanvas();
fillTextCanvas(txt, 0, 0, 1, 0, 32);
arr.push(display_hex);
// fillMatrix();
}
console.log(JSON.stringify(arr));
// startEvents();
}
findFirstPositive(b, a, i, c) {
c = (d, e) => e >= d ? (a = d + (e - d) / 2, 0 < b(a) && (a == d || 0 >= b(a - 1)) ? a : 0 >=
b(a) ? c(a + 1, e) : c(d, a - 1)) : -1
for (i = 1; 0 >= b(i);) i *= 2
return c(i / 2, i) | 0
}
getDPI() {
var dpi = findFirstPositive(x => matchMedia(`(max-resolution: ${x}dpi)`).matches);
return dpi
}
getImage() {
return this.canvas.toDataURL('image/png', 1.0);
}
}
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = Canvas;
}
The canvas does not respect your devices pixel ratio, this is not a specific electron issue.
The code you have copy and pasted from another StackOverflow won't work because you change the size/height again without respecting the ratio. If you uncomment it and adjust it correctly, it will work.
New to HTML canvas. I got a good pointer for the wave generation using Shovan Dhara
codes.
However i want to achieve a floating rectangle at the top of this wave. Any pointer would be useful.
Thanks.
P.S: find code below:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Oscillators</title>
<style type='text/css'>
body {
margin:0;
padding:0;
overflow:hidden;
background:#e6e5e5;
}
</style>
<script type='text/javascript'>
// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
//<![CDATA[
window.onload=function(){
/**
* Wave oscillators by Ken Fyrstenberg Nilsen
* http://abdiassoftware.com/
*
* CC-Attribute 3.0 License
*/
var ctx = canvas.getContext('2d'),
w, h;
canvas.width = w = window.innerWidth * 1.1;
canvas.height = h = window.innerHeight * 1;
var osc1 = new osc(),
osc2 = new osc(),
osc3 = new osc(),
horizon = h * 0.5;
count = 40,
step = Math.ceil(w / count),
//points = new Array(count);
buffer = new ArrayBuffer(count * 4),
points = new Float32Array(buffer);
osc1.max = 15;//h * 0.7;
osc2.max = 5;
osc2.speed = 0.03;
osc2.max = 5;
osc2.speed = 0.015;
function fill() {
for(var i = 0; i < count; i++) {
points[i] = mixer(osc1, osc2, osc3);
}
}
fill();
ctx.lineWidth = 20;
ctx.strokeStyle = '#0000';
ctx.fillStyle = '#1d96d3';
function loop() {
var i;
/// move points to the left
for(i = 0; i < count - 1; i++) {
points[i] = points[i + 1];
}
/// get a new point
points[count - 1] = mixer(osc1, osc2, osc3);
ctx.clearRect(0, 0, w, h);
//ctx.fillRect(0, 0, w, h);
/// render wave
ctx.beginPath();
ctx.moveTo(-5, points[0]);
for(i = 1; i < count; i++) {
ctx.lineTo(i * step, points[i]);
}
ctx.lineTo(w, h);
ctx.lineTo(-5, h);
ctx.lineTo(-5, points[1]);
ctx.stroke();
ctx.fill();
ctx.strokeRect(100,h/2,150,100);
}
/// oscillator object
function osc() {
this.variation = 0.4;
this.max = 150;
this.speed = 0.02;
var me = this,
a = 0,
max = getMax();
this.getAmp = function() {
a += this.speed;
if (a >= 2.0) {
a = 0;
max = getMax();
}
return max * Math.sin(a * Math.PI);
}
function getMax() {
return Math.random() * me.max * me.variation +
me.max * (1 - me.variation);
}
return this;
}
function mixer() {
var d = arguments.length,
i = d,
sum = 0;
if (d < 1) return 0;
while(i--) sum += arguments[i].getAmp();
return sum / d + horizon;
}
(function animloop(){
requestAnimFrame(animloop);
loop();
})();
}//]]>
</script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
I took width of the screen and divided it by points number then I calculated which point to use for the box Y coordinate for given X coordinate based on its dimensions. points are just Y coordinates, so the height of a wave in the point.
Those are my calculations:
var rectX = 500;
var rectWidth = 200;
var rectHeight = 100;
var centerX = rectX + rectWidth / 2;
var pointToUse = Math.floor(centerX / (w / points.length));
And I draw the box like this:
ctx.strokeRect(rectX, points[pointToUse] - rectHeight, rectWidth, rectHeight);
You can make it more submerged by adding some to points[pointToUse] - rectHeight
You may also add safety checks for points.length != 0 and (w / points.length) != 0
Here is working snippet:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Oscillators</title>
<style type='text/css'>
body {
margin:0;
padding:0;
overflow:hidden;
background:#e6e5e5;
}
</style>
<script type='text/javascript'>
// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
//<![CDATA[
window.onload=function(){
/**
* Wave oscillators by Ken Fyrstenberg Nilsen
* http://abdiassoftware.com/
*
* CC-Attribute 3.0 License
*/
var ctx = canvas.getContext('2d'),
w, h;
canvas.width = w = window.innerWidth * 1.1;
canvas.height = h = window.innerHeight * 1;
var osc1 = new osc(),
osc2 = new osc(),
osc3 = new osc(),
horizon = h * 0.5;
count = 40,
step = Math.ceil(w / count),
//points = new Array(count);
buffer = new ArrayBuffer(count * 4),
points = new Float32Array(buffer);
osc1.max = 15;//h * 0.7;
osc2.max = 5;
osc2.speed = 0.03;
osc2.max = 5;
osc2.speed = 0.015;
function fill() {
for(var i = 0; i < count; i++) {
points[i] = mixer(osc1, osc2, osc3);
}
}
fill();
ctx.lineWidth = 20;
ctx.strokeStyle = '#0000';
ctx.fillStyle = '#1d96d3';
var rectX = 200;
var rectWidth = 100;
var rectHeight = 50;
var centerX = rectX + rectWidth / 2;
var pointToUse = Math.floor(centerX / (w / points.length));
function loop() {
var i;
/// move points to the left
for(i = 0; i < count - 1; i++) {
points[i] = points[i + 1];
}
/// get a new point
points[count - 1] = mixer(osc1, osc2, osc3);
ctx.clearRect(0, 0, w, h);
//ctx.fillRect(0, 0, w, h);
/// render wave
ctx.beginPath();
ctx.moveTo(-5, points[0]);
for(i = 1; i < count; i++) {
ctx.lineTo(i * step, points[i]);
}
ctx.lineTo(w, h);
ctx.lineTo(-5, h);
ctx.lineTo(-5, points[1]);
ctx.stroke();
ctx.fill();
ctx.strokeRect(rectX, points[pointToUse] - rectHeight, rectWidth, rectHeight);
}
/// oscillator object
function osc() {
this.variation = 0.4;
this.max = 150;
this.speed = 0.02;
var me = this,
a = 0,
max = getMax();
this.getAmp = function() {
a += this.speed;
if (a >= 2.0) {
a = 0;
max = getMax();
}
return max * Math.sin(a * Math.PI);
}
function getMax() {
return Math.random() * me.max * me.variation +
me.max * (1 - me.variation);
}
return this;
}
function mixer() {
var d = arguments.length,
i = d,
sum = 0;
if (d < 1) return 0;
while(i--) sum += arguments[i].getAmp();
return sum / d + horizon;
}
(function animloop(){
requestAnimFrame(animloop);
loop();
})();
}//]]>
</script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
I want something like this site , look at mouse background in header section:
Link
when i check page source i found this:
<canvas id="header-canvas" width="1360" height="676"></canvas>
Take a look at source code and identify which JS plugins are being used.
I have pulled it apart and found its using green sock https://greensock.com
Take a look at http://codepen.io/elliottgg/pen/YpQBpZ
Scroll down to line 40 to see where the magic is happening
(function() {
var width, height, largeHeader, canvas, ctx, points, target, animateHeader = true;
// Main
initHeader();
initAnimation();
addListeners();
function initHeader() {
width = window.innerWidth;
height = window.innerHeight;
target = {x: width/2, y: height/2};
largeHeader = document.getElementById('header');
largeHeader.style.height = height+'px';
canvas = document.getElementById('header-canvas');
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext('2d');
// create points
points = [];
for(var x = 0; x < width; x = x + width/20) {
for(var y = 0; y < height; y = y + height/20) {
var px = x + Math.random()*width/20;
var py = y + Math.random()*height/20;
var p = {x: px, originX: px, y: py, originY: py };
points.push(p);
}
}
// for each point find the 5 closest points
for(var i = 0; i < points.length; i++) {
var closest = [];
var p1 = points[i];
for(var j = 0; j < points.length; j++) {
var p2 = points[j]
if(!(p1 == p2)) {
var placed = false;
for(var k = 0; k < 5; k++) {
if(!placed) {
if(closest[k] == undefined) {
closest[k] = p2;
placed = true;
}
}
}
for(var k = 0; k < 5; k++) {
if(!placed) {
if(getDistance(p1, p2) < getDistance(p1, closest[k])) {
closest[k] = p2;
placed = true;
}
}
}
}
}
p1.closest = closest;
}
// assign a circle to each point
for(var i in points) {
var c = new Circle(points[i], 2+Math.random()*2, 'rgba(255,255,255,0.8)');
points[i].circle = c;
}
}
// Event handling
function addListeners() {
if(!('ontouchstart' in window)) {
window.addEventListener('mousemove', mouseMove);
}
window.addEventListener('scroll', scrollCheck);
window.addEventListener('resize', resize);
}
function mouseMove(e) {
var posx = posy = 0;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
}
else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
target.x = posx;
target.y = posy;
}
function scrollCheck() {
if(document.body.scrollTop > height) animateHeader = false;
else animateHeader = true;
}
function resize() {
width = window.innerWidth;
height = window.innerHeight;
largeHeader.style.height = height+'px';
canvas.width = width;
canvas.height = height;
}
// animation
function initAnimation() {
animate();
for(var i in points) {
shiftPoint(points[i]);
}
}
function animate() {
if(animateHeader) {
ctx.clearRect(0,0,width,height);
for(var i in points) {
// detect points in range
if(Math.abs(getDistance(target, points[i])) < 4000) {
points[i].active = 0.3;
points[i].circle.active = 0.6;
} else if(Math.abs(getDistance(target, points[i])) < 20000) {
points[i].active = 0.1;
points[i].circle.active = 0.3;
} else if(Math.abs(getDistance(target, points[i])) < 40000) {
points[i].active = 0.02;
points[i].circle.active = 0.1;
} else {
points[i].active = 0.0;
points[i].circle.active = 0.0;
}
drawLines(points[i]);
points[i].circle.draw();
}
}
requestAnimationFrame(animate);
}
function shiftPoint(p) {
TweenLite.to(p, 1+1*Math.random(), {x:p.originX-50+Math.random()*100,
y: p.originY-50+Math.random()*100, ease:Circ.easeInOut,
onComplete: function() {
shiftPoint(p);
}});
}
// Canvas manipulation
function drawLines(p) {
if(!p.active) return;
for(var i in p.closest) {
ctx.beginPath();
ctx.moveTo(p.x, p.y);
ctx.lineTo(p.closest[i].x, p.closest[i].y);
ctx.strokeStyle = 'rgba(255,255,255,'+ p.active+')';
ctx.stroke();
}
}
function Circle(pos,rad,color) {
var _this = this;
// constructor
(function() {
_this.pos = pos || null;
_this.radius = rad || null;
_this.color = color || null;
})();
this.draw = function() {
if(!_this.active) return;
ctx.beginPath();
ctx.arc(_this.pos.x, _this.pos.y, _this.radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'rgba(255,255,255,'+ _this.active+')';
ctx.fill();
};
}
// Util
function getDistance(p1, p2) {
return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2);
}
I'm still making Asteroids game in canvas in html5. Everything were going good, but now I'm in deadlock. Collision works, but I have no idea how to split an asteroid after shooting in it.
Here is code:
window.addEventListener('keydown',doKeyDown,true);
window.addEventListener('keyup',doKeyUp,true);
var canvas = document.querySelector('#pageCanvas');
var context = canvas.getContext('2d');
var angle = 0;
var H = /*500;*/window.innerHeight; //*0.75,
var W = /*500;*/window.innerWidth; //*0.75;
canvas.width = W;
canvas.height = H;
var xc = W/2; //zeby bylo w centrum :v
var yc = H/2; //jw.
var x = xc;
var y = yc;
var dv = 0.2;
var dt = 1;
var vx = 0;
var vy = 0;
var fps = 30;
var maxVel = 5;
var maxVelLeft = -5;
var frict = 0.99;
var brakes = 0.90;
var keys = new Array();
var fire = false;
var points = 0;
var lives = 3;
var randomize = true;
//zamiennik do setintervala
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
var fps = 30;
var now;
var then = Date.now();
var interval = 1000/fps;
var delat;
//laser
var laserF = false;
var lasery = [];
var shootVel = 12; //velocity of laser
//asteroids
var asteroidy = [];
var newasteroid1 ={
ax : ((Math.round(Math.random()*1000))%500),
ay : ((Math.round(Math.random()*1000))%500),
avx : 1*(Math.random() > 0.5 ? -1 : 1),
avy : 1*(Math.random() > 0.5 ? -1 : 1),
ar : 30,
aangle : 3,
colour : "gray"
};
asteroidy.push(newasteroid1);
var newasteroid2 ={
ax : ((Math.round(Math.random()*1000))%500),
ay : ((Math.round(Math.random()*1000))%500),
avx : 1*(Math.random() > 0.5 ? -1 : 1),
avy : 1*(Math.random() > 0.5 ? -1 : 1),
ar : 30,
aangle : 2,
colour : "gray"
};
asteroidy.push(newasteroid2);
var newasteroid3 ={
ax : ((Math.round(Math.random()*1000))%500),
ay : ((Math.round(Math.random()*1000))%500),
avx : 1*(Math.random() > 0.5 ? -1 : 1),
avy : 1*(Math.random() > 0.5 ? -1 : 1),
ar : 30,
aangle : 2,
colour : "gray"
};
asteroidy.push(newasteroid3);
var newasteroid4 ={
ax : ((Math.round(Math.random()*1000))%500),
ay : ((Math.round(Math.random()*1000))%500),
avx : 1*(Math.random() > 0.5 ? -1 : 1),
avy : 1*(Math.random() > 0.5 ? -1 : 1),
ar : 30,
aangle : 0,
colour : "fuchsia"
};
asteroidy.push(newasteroid4);
function doKeyUp(evt){
keys[evt.keyCode] = false;
fire = false;
if (laserF) {
var newlaser ={
lx: x,
ly: y,
//lw : 4,
//lh : 4,
lr : 2,
lvx : Math.cos(convertToRadians(angle)),
lvy : Math.sin(convertToRadians(angle))
}
lasery.push(newlaser);
laserF = false;
}
}
function doKeyDown(evt){
keys[evt.keyCode] = true;
if(40 in keys && keys[40]){
if(randomize){
x = (Math.round(Math.random()*1000))%W;
y = (Math.round(Math.random()*1000))%H;
vx = 0;
vy = 0;
randomize = false;
setTimeout(function(){randomize = true;}, 2000);
}
}
}
function drawPoints(){
context.save();
context.setTransform(1,0,0,1,0,0);
context.beginPath();
context.fillText("Score: " + points, 50, 50);
context.fillStyle = "#FFFFFF";
context.fill();
context.closePath();
context.restore();
}
function drawLives(){
context.save();
context.setTransform(1,0,0,1,0,0);
context.beginPath();
context.fillText(lives + " lives left", 150, 50);
context.fillStyle = "#FFFFFF";
context.fill();
context.closePath();
context.restore();
}
function drawAsteroids(idx){
var asteroid = asteroidy[idx];
context.save();
context.setTransform(1,0,0,1,0,0);
context.rotate(0);
context.translate(asteroid.ax, asteroid.ay);
context.rotate(asteroid.aangle);
context.translate(-25,-25);
context.beginPath();
context.fillText(asteroid.ax + " " + asteroid.ay, 0,50);
context.arc(0, 0, asteroid.ar, 0, 2 * Math.PI, false);
context.fillStyle = asteroid.colour;
context.fill();
context.closePath();
/*beginPath();
moveTo(0,0);
lineTo()*/
context.restore();
}
function moveAsteroids(idx){
var asteroid = asteroidy[idx]
asteroid.ax += asteroid.avx;
asteroid.ay += asteroid.avy;
asteroid.aangle += 0.009;
if(asteroid.ax > W){
asteroid.ax = 0 -25;
}
else{
if(asteroid.ax < -25){
asteroid.ax = W;
}
}
if(asteroid.ay > H){
asteroid.ay = 0 -25;
}
else{
if(asteroid.ay < -25){
asteroid.ay = H;
}
}
}
function drawLaser(idx) {
var laser = lasery[idx];
context.save();
context.translate(laser.lx,laser.ly);
context.fillStyle = "red";
//context.fillText(laser.lx + " " + laser.ly,10,10);
//context.fillRect(0,0,laser.lw,laser.lh);
context.beginPath();
context.arc(0, 0, laser.lr, 0, 2 * Math.PI, false);
context.fillStyle = "red";
context.fill();
context.closePath();
context.restore();
}
function moveLaser(idx) {
var laser = lasery[idx];
laser.lx += laser.lvx * shootVel;
laser.ly += laser.lvy * shootVel;
if (laser.lx > W || laser.lx < 0 || laser.ly > H || laser.ly < 0) {
lasery.splice(idx, 1);
}
}
//OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
function ogienZdupy(){
context.fillStyle = "red";
context.beginPath();
context.moveTo(-2,2);
context.lineTo(2,10);
context.lineTo(-2,18);
context.lineTo(-25,10);
context.lineTo(-2,2);
context.strokeStyle = "red";
context.stroke();
}
function convertToRadians(degree) {
return degree*(Math.PI/180);
}
function incrementAngle() {
angle += 5;
if(angle > 360){
angle = 0;
}
}
function decrementAngle(){
angle -= 5;
if(angle > 360){
angle = 0;
}
}
function xyVelocity(){
vx += dv * Math.cos(convertToRadians(angle)); //* friction;
vy += dv * Math.sin(convertToRadians(angle)); //* friction;
if(vx > maxVel){
vx = maxVel;
}
if(vy < maxVelLeft){
vy = maxVelLeft;
}
if(vx < maxVelLeft){
vx = maxVelLeft;
}
if(vy > maxVel){
vy = maxVel;
}
}
function shipMovement(){
if(66 in keys && keys[66]){ //it's B
vx = 0;
vy = 0;
}
if(38 in keys && keys[38]){
xyVelocity();
fire = true;
}
if(37 in keys && keys[37]){
decrementAngle();
};
if (39 in keys && keys[39]){
incrementAngle();
};
if (32 in keys && keys[32]){
laserF = true;
};
}
function xyAndFriction(){
x += vx * dt;
y += vy * dt;
vx *= frict;
vy *= frict;
}
function outOfBorders(){
if(x > W){
x = x - W;
}
if(x< 0){
x = W;
}
if(y > H){
y = y - H;
}
if(y < 0){
y = H;
}
}
function blazeatron420(){ //the ship
context.beginPath();
context.moveTo(0,0);
context.lineTo(20,10);
context.lineTo(0,20);
context.lineTo(7,10);
context.lineTo(0,0);
context.strokeStyle = "green";
context.stroke();
}
function space(){
context.fillStyle = "black";
context.fillRect(0,0,W,H);
}
/*
function superLaserCollider(){
for(var i in asteroidy){
var ax = asteroidy[i].ax,
ay = asteroidy[i].ay,
ar = asteroidy[i].ar
for(var j in lasery){
var xl = lasery[j].lx,
yl = lasery[j].ly,
rl = lasery[j].lr
}
}
/*var dx = Math.abs(ax - (xl+wl/2));
var dy = Math.abs(ay - (yl+yl/2));
if(dx > ar + wl){
return (false);
}
if(dy > ar + hl){
return (false);
}
if(dx <= wl){
return (true);
}
if(dy <= hl){
return (true);
}
var dx = dx - wl;
var dy = dy - hl;
return(dx * dx + dy * dy <= ar * ar);
var dx = ax - xl;
var dy = ay - yl;
var distance = Math.sqrt(dx * dx + dy * dy);
if(xl > ax && yl > ax){
console.log("kolizja");
}
}
*/
function bigAsteroidExplosion(idx){
var asteroid = asteroidy[idx];
context.clearRect(asteroid.ax, asteroid.ay, 100, 100);
}
function superLaserCollider(){
for(var i in asteroidy){
var ax = asteroidy[i].ax,
ay = asteroidy[i].ay,
ar = asteroidy[i].ar;
for(var j in lasery){
var xl = lasery[j].lx,
yl = lasery[j].ly,
rl = lasery[j].lr;
var dx = ax - xl;
var dy = ay - yl;
var distance = Math.sqrt(dx * dx + dy * dy);
if(distance < ar + rl){
console.log("kabom");
points = points + 100;
//alert("BOOM");
console.log(points);
}
}
}
}
/*
context.beginPath();
context.fillText(points, 100, 100);
context.fillStyle = "#FFFFFF";
context.fill();
context.closePath();
*/
function drawEverything() {
shipMovement();
xyAndFriction();
outOfBorders();
//context.save();
//;
space();
context.save();
context.translate(x,y);
//context.translate(25,25);
context.rotate(convertToRadians(angle));
context.translate(-7,-10);
if(fire){
ogienZdupy();
}
context.fillStyle = "green";
//context.fillText(vx + " km/h",50,50);
/*context.fillText("dupa",-30,0);
context.beginPath();
context.moveTo(-20,5);
context.lineTo(-5,10);
context.strokeStyle = "green"; //KOLOR LINII ;_;
context.stroke();*/
if(asteroidy.length > 0 ){
for (var tmp in asteroidy){
drawAsteroids(tmp);
moveAsteroids(tmp);
}
}
//putAsteroids();
blazeatron420();
//shootAsteroid(idx);
context.translate(-x+7,-y+10);
drawPoints();
drawLives();
context.restore();
console.log(asteroidy.length);
//superCollider();
//for(var i = 0; i < asteroidy.length; i++)
if(lasery.length > 0){
for (var tmp in lasery) {
drawLaser(tmp);
moveLaser(tmp);
}
}
superLaserCollider();
}
//setInterval(drawEverything, 20);
function draw(){
requestAnimationFrame(draw);
now = Date.now();
delta = now - then;
if (delta > interval){
then = now - (delta % interval);
}
drawEverything();
}
draw();
body{
margin:0;
padding:0;
overflow:hidden;
}
<body>
<canvas id="pageCanvas" style="display:block">
You do not have a canvas enabled browser. Please, stop using IE :P
</canvas>
</body>
I am currently playing around with a blob code and have a small problem.
The problem is that sometimes the blob gets inverted so the white color gets inside the blob itself and makes a white hole in it which I don't really want.
Any suggestions on how to fix this, so the blob stays all the time as one little nice piece?
This is the one im playing around with:
http://wonderfl.net/c/rYzh
class Blob extends Sprite
{
private var speed :Number = .01;
private var grav :Number = .25;
private var dist :Number = 27;
private var k :Number = .55;
private var damp :Number = .99;
private var cx :Number = 370;
private var cy :Number = 0;
private var points :Array = [];
private var mids :Array = [];
private var numPoints:Number = 30;
private var oneSlice :Number = Math.PI * 2 / numPoints;
private var radius :Number = 100;
public function Blob()
{
for (var i:Number = 0; i < numPoints; i++)
{
var angle:Number = oneSlice * i;
var obj:Object = {x:Math.cos(angle) * radius + cx, y:Math.sin(angle) * radius + cy, a:angle - Math.PI / 2, wave:i*.08, vx:0, vy:0};
points[i] = obj;
}
this.addEventListener(Event.ENTER_FRAME, update);
}
private function update(event:Event):void
{
this.graphics.clear();
this.graphics.lineStyle(1, 0x666666, 50);
this.graphics.beginFill(0x000000, 100);
for (var i:Number = 0; i < numPoints-1; i++)
{
mids[i] = {x:(points[i].x + points[i + 1].x) / 2, y:(points[i].y + points[i + 1].y) / 2};
}
mids[i] = {x:(points[i].x + points[0].x) / 2, y:(points[i].y + points[0].y) / 2};
this.graphics.moveTo(mids[0].x, mids[0].y);
for (var j:Number = 0; j < numPoints - 1; j++)
{
this.graphics.curveTo(points[j+1].x, points[j+1].y, mids[j+1].x, mids[j+1].y);
}
this.graphics.curveTo(points[0].x, points[0].y, mids[0].x, mids[0].y);
this.graphics.endFill();
var point:Object;
for (var k:Number = 0; k < numPoints - 1; k++)
{
point = points[k];
spring(point, points[k + 1]);
mouseSpring(point);
}
spring(points[k], points[0]);
mouseSpring(points[k]);
for (var l:Number = 0; l < numPoints; l++)
{
point = points[l];
point.vx *= damp;
point.vy *= damp;
point.vy += grav;
point.x += point.vx;
point.y += point.vy;
if (point.y > stage.stageHeight)
{
point.y = stage.stageHeight;
point.vy = 0;
}
if (point.x < 20)
{
point.x = 20;
point.vx = 0;
}
else if (point.x > stage.stageWidth)
{
point.x = stage.stageWidth;
point.vx = 0;
}
}
}
private function spring(p0:Object, p1:Object):void
{
var dx:Number = p0.x - p1.x;
var dy:Number = p0.y - p1.y;
var angle:Number = p0.a+Math.sin(p0.wave += speed)*2;
var tx:Number = p1.x + dist * Math.cos(angle);
var ty:Number = p1.y + dist * Math.sin(angle);
var ax:Number = (tx - p0.x) * k;
var ay:Number = (ty - p0.y) * k;
p0.vx += ax * .5;
p0.vy += ay * .5;
p1.vx -= ax * .5;
p1.vy -= ay * .5;
}
private function mouseSpring(p:Object):void
{
var dx:Number = p.x - stage.mouseX;
var dy:Number = p.y - stage.mouseY;
var dist:Number = Math.sqrt(dx * dx + dy * dy);
if (dist < 40)
{
var angle:Number = Math.atan2(dy, dx);
var tx:Number = stage.mouseX + Math.cos(angle) * 40;
var ty:Number = stage.mouseY + Math.sin(angle) * 40;
p.vx += (tx - p.x) * k;
p.vy += (ty - p.y) * k;
}
}
}
By default, the Graphics APIs use an evenOdd winding, which means if a filled path overlaps itself, it negates the fill.
You need to use the Graphics.drawPath function with a winding value of "nonZero". This will cause it not to negate when the path overlaps itself. Check out this little demo, make a shape that overlaps itself, and switch the winding from evenOdd to nonZero to see how it works.
As for translating your code, instead of using graphics.moveTo() and .curveTo() calls in your update() routine, you'll need to build up a description of your path (aka, the inputs to drawPath) and pass them into graphics.drawPath() last. Adobe shows an example here.