JavaScript canvas - I want to remove the scrollbar - javascript

JavaScript canvas - I want to remove the x-axis scrollbar.
Is it to do with innerWidth? Or is it something to do with my device/browser - I'm on a MacBook Air and using google chrome.
var canvas = document.getElementById('sky');
var ctx = canvas.getContext('2d')
var w = window.innerWidth;
var h = window.innerHeight;
canvas.width = w;
canvas.height = h;
// GENERATE THE stars
var mf = 10000; //QUANTITY OF stars
var flakes = [];
//loop through empty stars and apply attributes('width,height')
for(var i = 0; i < mf; i++)
{
flakes.push({
x: Math.random() * w,
y: Math.random() * h,
r: Math.random() * 2, // radius of each star = min 2px max 7px
d: Math.random() + 1// like the weight, how far they would fall
})
}
//draw flakes on the canvas
function drawFlakes()
{
ctx.clearRect(0, 0, w, h); // clears canvas
ctx.fillStyle = "#ffff00"; // fill the canvas or shapes will be white
ctx.beginPath(); // about to begin a path or draw shape
for(var i = 0; i < mf; i++) // going through each star
{
var f = flakes[i]; // grabbing fstar
ctx.moveTo(f.x, f.y);
ctx.arc(f.x, f.y, f.r, 0, Math.PI*1, true);
}
ctx.fill(); // fills flakes
moveFlakes();
}
// animate flakes
var angle = 0; // controls movement of flakes
function moveFlakes(){
angle += 0.01;
for(var i = 0; i < mf; i++)
{
//store current flake
var f = flakes[i];
//update x any coorodinates of each flake
f.y += Math.pow(f.d, 2) + 1;
f.x += Math.sin(angle) * 60;
//if snows flakes reach bottom, send a new one to the top
if(f.y > h) {
flakes[i] = {
x: Math.random()* w,
y: 0,
r: f.r,
d: f.d
}
}
}
}
setInterval(drawFlakes, 25);
}

Try adding this style to body tag overflow: hidden

Related

How to generate random non-overlapping polygons without free spaces

I need to generate random non-overlapping polygons without free spaces (. They can have any shape.
The only thing I found is an example that uses p5.js to create only non-overlapping circles, but free spaces are present.
Does anyone know how to do it?
// Uses P5.js for canvas creation and drawing
function setup() {
var circles = [],
circle = {},
overlapping = false,
NumCircles = 4000,
protection = 1000,
counter = 0,
canvasWidth = window.innerWidth,
canvasHeight = window.innerHeight;
createCanvas(canvasWidth, canvasHeight);
// populate circles array
// brute force method continues until # of circles target is reached
// or until the protection value is reached
while (circles.length < NumCircles &&
counter < protection) {
circle = {
x: random(width),
y: random(height),
r: random(3, 36)
};
overlapping = false;
// check that it is not overlapping with any existing circle
// another brute force approach
for (var i = 0; i < circles.length; i++) {
var existing = circles[i];
var d = dist(circle.x, circle.y, existing.x, existing.y)
if (d < circle.r + existing.r) {
// They are overlapping
overlapping = true;
// do not add to array
break;
}
}
// add valid circles to array
if (!overlapping) {
circles.push(circle);
}
counter++;
}
// circles array is complete
// draw canvas once
background("#233")
fill("#2AC1A6");
noStroke();
for (var i = 0; i < circles.length; i++) {
ellipse(circles[i].x, circles[i].y,
circles[i].r*2, circles[i].r*2);
}
}
* {
padding: 0;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
Your question is not very specific...
random non-overlapping polygons without free spaces
Rectangles are polygons, let's make a bunch of those with random sizes and colors
Here is a starting point:
canvas = document.getElementById('c');
ctx = canvas.getContext('2d');
var colors = ["red", "blue", "orange", "green", "yellow"]
h = Math.floor(canvas.height / Math.floor(Math.random() * 15 + 4))
for (y = 0; y < canvas.height; y += h) {
w = Math.floor(canvas.width / Math.floor(Math.random() * 15 + 4))
for (x = 0; x < canvas.width; x += w) {
c = colors[Math.floor(Math.random() * 10) % 5]
draw(x, y, w, h, c)
}
}
function draw(x, y, w, h, color) {
ctx.beginPath();
ctx.rect(x, y, w, h)
ctx.stroke();
ctx.fillStyle = color
ctx.fill();
}
<canvas id="c"></canvas>
Here is a function to help you draw "random" polygons:
var ctx = document.getElementById('c').getContext('2d');
function polygon(sides, size, Xcenter, Ycenter, offset) {
ctx.beginPath();
ctx.moveTo(Xcenter + size * Math.cos(offset), Ycenter + size * Math.sin(offset));
for (var i = 1; i <= sides; i += 1) {
x = Xcenter + size * Math.cos(i * 2 * Math.PI / sides +offset)
y = Ycenter + size * Math.sin(i * 2 * Math.PI / sides +offset)
ctx.lineTo(x, y);
}
ctx.stroke();
}
arr = [3, 4, 5, 6, 7];
arr.sort(() => Math.random() - 0.5);
for (var i = 1; i <= 5; i += 1) {
offset = Math.random() * 5
polygon(arr[i-1], 40, 85*i, 60, offset)
}
<canvas id="c" width=600></canvas>

Creating a checkered board with pieces in HTML5 canvas

I am experimenting with canvas in HTML and JS and attempting to draw a canvas of a chess board with 16 pieces on each side of it. I was able to create the chess board but am stuck on how I would draw just specifically the 16 pieces on each side (The pieces can just be circles so just one side with 16 red circles, one side with 16 blue circles).
I don't know why this is so confusing to me, I know you probably just need a for loop stopping at the specific coordinates but to get different colored pieces on each side as well as stopping at certain part is giving me trouble.
I would just like assistance on where in my code would I be placing the chess pieces in. If you could just modify my current code and place comments on where you made the changes so I could see then that would be very appreciated.
Here is what I have so far to make the checkers board:
<canvas id="canvas" width="300" height="300"></canvas>
function drawCheckeredBackground(can, nRow, nCol) {
var ctx = can.getContext("2d");
var w = can.width;
var h = can.height;
nRow = nRow || 8;
nCol = nCol || 8;
w /= nCol;
h /= nRow;
for (var i = 0; i < nRow; ++i) {
for (var j = 0, col = nCol / 2; j < col; ++j) {
ctx.rect(2 * j * w + (i % 2 ? 0 : w), i * h, w, h);
}
}
ctx.fill();
}
var canvas = document.getElementById("canvas");
drawCheckeredBackground(canvas);
Here is how I want the chess board to look like, with 16 pieces on each side like so. I just quickly made this example in paint:
https://i.imgur.com/BvbxzSZ.png
This isn't the most beautiful solution possible, but it should offer some basic ideas and is adjustable using your step variable idea. Chances are, you'll need to refactor when going for actual pieces.
const drawBoard = (ctx, step) => {
for (let i = 0; i < 8; i++) {
for (let j = 0; j < 8; j++) {
ctx.fillStyle = (i + j) & 1 ? "black" : "white";
ctx.fillRect(j * step, i * step, step, step);
}
}
};
const drawPieces = (ctx, y, color, step) => {
ctx.fillStyle = color;
for (let i = y; i < 2 * step + y; i += step) {
for (let j = step / 2; j < 8 * step; j += step) {
ctx.beginPath();
ctx.arc(j, i - step / 2, step / 3, 0, Math.PI * 2);
ctx.fill();
}
}
};
const step = 60;
const c = document.createElement("canvas");
c.height = c.width = step * 8;
document.body.appendChild(c);
const ctx = c.getContext("2d");
drawBoard(ctx, step);
drawPieces(ctx, step, "red", step);
drawPieces(ctx, step * 7, "blue", step);
Play with it at JSFiddle.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
display: block;
margin: auto;
border: solid 1px white;
border-radius: 10px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
// Self executing function
void function() {
// Turn on strict js rules for this scope
"use strict";
// Classes
function ChessPeice(x,y,radius) {
this.x = x || 0.0;
this.y = y || 0.0;
this.radius = radius || 1.0;
}
ChessPeice.prototype = {
tick: function() {
},
render: function(ctx) {
ctx.moveTo(
this.x + this.radius,
this.y
);
ctx.arc(
this.x,
this.y,
this.radius,
0.0,
2.0 * Math.PI,
false
);
}
};
// Constructor, when called with 'new' creates an object and puts it
// in the 'this' variable, new properties can then be added to it.
function Chessboard(width,height) {
this.boardWidth = width || 1;
this.boardHeight = height || 1;
this.tileWidth = this.boardWidth / this.H_TILE_COUNT;
this.tileHeight = this.boardHeight / this.V_TILE_COUNT;
this.whitePeices = [];
this.blackPeices = [];
for (var y = 0; y < 2; ++y) {
for (var x = 0; x < this.V_TILE_COUNT; ++x) {
this.whitePeices.push(
new ChessPeice(
x * this.tileWidth + (this.tileWidth >> 1),
y * this.tileHeight + (this.tileHeight >> 1),
this.CHESS_PIECE_RADIUS
)
);
this.blackPeices.push(
new ChessPeice(
x * this.tileWidth + (this.tileWidth >> 1),
(this.V_TILE_COUNT - 1 - y) * this.tileHeight + (this.tileHeight >> 1),
this.CHESS_PIECE_RADIUS
)
);
}
}
}
// Prototype object, all objects created with 'new Chessboard()'
// will share the properties in the prototype, use it for constant values
// & class functions
Chessboard.prototype = {
H_TILE_COUNT: 8, // How many white & black tiles per axis?
V_TILE_COUNT: 8,
EDGE_THICKNESS: 10.0,
EDGE_COLOUR: "#603E11FF",
WHITE_TILE_COLOUR: "#BBBBBBFF",
BLACK_TILE_COLOUR: "#555555FF",
CHESS_PIECE_RADIUS: 5.0,
WHITE_PIECE_COLOUR: "#EEEEEEFF",
BLACK_PIECE_COLOUR: "#333333FF",
tick: function() {
// You can add game logic here
},
render: function(ctx) {
// Draw white tiles
var x = 0;
var y = 0;
var totalTiles = this.H_TILE_COUNT * this.V_TILE_COUNT;
ctx.fillStyle = this.WHITE_TILE_COLOUR;
ctx.beginPath();
for (var i = 0; i < totalTiles; ++i) {
ctx.rect(
x * this.tileWidth,
y * this.tileHeight,
this.tileWidth,
this.tileHeight
);
x += 2;
if (x >= this.H_TILE_COUNT) {
x = this.H_TILE_COUNT - x + 1;
++y;
}
}
ctx.fill();
// Draw black tiles
x = 1;
y = 0;
ctx.fillStyle = this.BLACK_TILE_COLOUR;
ctx.beginPath();
for (var i = 0; i < totalTiles; ++i) {
ctx.rect(
x * this.tileWidth,
y * this.tileHeight,
this.tileWidth,
this.tileHeight
);
x += 2;
if (x >= this.H_TILE_COUNT) {
x = this.H_TILE_COUNT - x + 1;
++y;
}
}
ctx.fill();
// Draw edge
ctx.lineWidth = this.EDGE_THICKNESS >> 1;
ctx.strokeStyle = this.EDGE_COLOUR;
ctx.beginPath();
ctx.rect(0,0,this.boardWidth,this.boardHeight);
ctx.stroke();
// Draw white pieces
ctx.lineWidth = 2;
ctx.strokeStyle = "#000000FF";
ctx.fillStyle = this.WHITE_PIECE_COLOUR;
ctx.beginPath();
for (var i = 0; i < this.whitePeices.length; ++i) {
this.whitePeices[i].render(ctx);
}
ctx.fill();
ctx.stroke();
// Draw black pieces
ctx.lineWidth = 2;
ctx.strokeStyle = "#000000FF";
ctx.fillStyle = this.BLACK_PIECE_COLOUR;
ctx.beginPath();
for (var i = 0; i < this.blackPeices.length; ++i) {
this.blackPeices[i].render(ctx);
}
ctx.fill();
ctx.stroke();
}
};
// Variables
var canvasWidth = 160;
var canvasHeight = 160;
var canvas = null;
var ctx = null;
var board = null;
// Game Loop
function loop() {
// Tick (Update game logic)
board.tick();
// Render
ctx.fillStyle = "gray";
ctx.fillRect(0,0,canvasWidth,canvasHeight);
board.render(ctx);
//
requestAnimationFrame(loop);
}
// Entry Point (Runs when the page loads)
onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
ctx = canvas.getContext("2d");
board = new Chessboard(canvasWidth,canvasHeight);
loop();
}
}();
</script>
</body>
</html>

How do I draw a box around multiple shapes in html5 canvas

I am trying to draw a box around multiple shapes in canvas to say that those shapes are related like a group.
Tried as below :
var ctx = c.getContext("2d"),
radius = 10,
rect = c.getBoundingClientRect(),
ctx.fillText("Draw something here..", 10, 10);
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(250, 300, radius, 0, 6.28);
ctx.fill();
ctx.fillStyle = "yellow";
ctx.beginPath();
ctx.arc(200, 100, radius, 0, 10.28);
ctx.fill();
ctx.fillStyle = "brown";
ctx.beginPath();
ctx.arc(350, 210, radius, 0, 10.28);
ctx.fill();
var x = (250+200+350)/3;
var y = (300+100+210)/3;
var radius = Math.sqrt((x1*x1)+(y1*y1));
var _minX = x - radius;
var _minY = y - radius;
var _maxX = x + radius;
var _maxY = y + radius;
ctx.rect(_minX,_minY,(_maxX-_minX+2),(_maxY-_minY+2));
ctx.stroke();
But it is not drawing properly.
How to get bounding box coordinates for canvas content? this link explains only for the path not for the existing shapes.
Below is the image how I want to draw:
Fabric <-- See if this library helps had used this for one of my project it is simple and quick.
This Code is not production ready, Or the best solution, but it works in "most cases".
I'm using the imageData, to check for non-white pixel. (If NOT 0 - RGBA Pixel ==> Object) and with this it narrows the possible Rectangle down. You would also need to tweak it, if you don't want the text to be in the Rectangle.
This code could / should be optimized.
EDIT: Now I am only checking if an Alpha Value is set. And some Random Object creation to test multiple Outcomes
Info: Objects that are clipped/cut happen, because they are out of the canvas size.
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var colors = ["red", "blue", "green", "black"];
ctx.fillText("Draw something here..", 0, 10);
/** CREATEING SOME RANDOM OBJECTS (JUST FOR TEST) **/
createRandomObjects();
function createRandomIntMax(max){
return parseInt(Math.random() * 1000 * max) % max + 1;
}
function createRandomObjects(){
var objectsToDraw = createRandomIntMax(20);
for(var idx = 0; idx < objectsToDraw; idx++){
ctx.fillStyle = colors[createRandomIntMax(colors.length)];
ctx.beginPath();
ctx.arc(createRandomIntMax(c.width), createRandomIntMax(c.height), createRandomIntMax(30), 0, 2 * Math.PI);
ctx.fill();
}
}
/** GETTING IMAGE DATA **/
var myImageData = ctx.getImageData(0, 0, c.width, c.height);
/** FINDING BORDERS **/
findBorders(myImageData.data);
function findBorders(imageData) {
var result = {
left: c.width,
top: c.height,
right: -1,
bottom: -1
}
var idx = 0;
var lineLow = -1;
var lineHigh = -1;
var currentLine = 0;
var currentPoint, helper;
while (idx < imageData.length) {
currentPoint = imageData[idx + 3];
/** CHECKING FOR OBJECT **/
if (currentPoint != 0) {
helper = parseInt(idx % (c.width * 4)) / 4;
if (lineLow < 0) {
lineLow = helper;
lineHigh = helper;
} else {
lineHigh = helper;
}
}
if (idx !== 0 && (idx % (c.width * 4)) === 0) {
currentLine = idx / (c.width * 4);
// Updating the Border Points
if (lineLow > -1) {
result.left = Math.min(lineLow, result.left);
result.top = Math.min(currentLine, result.top);
result.right = Math.max(lineHigh, result.right);
result.bottom = Math.max(currentLine, result.bottom);
}
lineLow = -1;
lineHigh = -1;
}
idx += 4;
}
ctx.rect(result.left, result.top, result.right - result.left, result.bottom - result.top);
ctx.stroke()
}
<canvas id="canvas"></canvas>
USE getBoundingClientRect() to get the exact boundaries

How to make blur effect particles in javascript

Hi I want to make a blur effect particle like this:
Can I use shadowBlur and shadowOffsetX/shadowOffsetY to do this? The actual shine will glow and fade a little bit repeatedly, so if I have to write some kind of animation how can I achieve this?
I have tried this code (jsfiddle example) but it doesn't look like the effect. So I wonder how to blur and glow the particle at the same time?
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ra = window.requestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.oRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function(callback) {
window.setTimeout(callback, 1000 / 60);
};
class Particle {
constructor(options) {
this.ctx = options.context;
this.x = options.x;
this.y = options.y;
this.radius = options.radius;
this.lightSize = this.radius;
this.color = options.color;
this.lightDirection = true;
}
glow() {
const lightSpeed = 0.5;
this.lightSize += this.lightDirection ? lightSpeed : -lightSpeed;
if (this.lightSize > this.radius || this.lightSize < this.radius) {
this.lightDirection = !this.lightDirection;
}
}
render() {
this.ctx.clearRect(0, 0, canvas.width, canvas.height);
this.glow();
this.ctx.globalAlpha = 0.5;
this.ctx.fillStyle = this.color;
this.ctx.beginPath();
this.ctx.arc(this.x, this.y, this.lightSize,
0, Math.PI * 2
);
this.ctx.fill();
this.ctx.globalAlpha = 0.62;
this.ctx.beginPath();
this.ctx.arc(this.x, this.y, this.radius * 0.7, 0, Math.PI * 2);
this.ctx.shadowColor = this.color;
this.ctx.shadowBlur = 6;
this.ctx.shadowOffsetX = 0;
this.ctx.shadowOffsetY = 0;
this.ctx.fill();
}
}
var particle = new Particle({
context: ctx,
x: 60,
y: 80,
radius: 12,
color: '#4d88ff'
});
function run() {
particle.render();
ra(run);
}
run();
<canvas id='canvas'></canvas>
There are several ways to do this. For a particle system my option is to pre render the blur using a blur filter. A common filter is the convolution filter. It uses a small array to determine the amount neighboring pixels contribute to each pixel of the image. You are best to look up convolution functions to understand it.
Wiki Convolution and Wiki Gaussian blur for more info.
I am not much of a fan of the standard Gaussian blur or the convolution filter used so in the demo snippet below you can find my version that I think creates a much better blur. The convolution blur filter is procedurally created and is in the imageTools object.
To use create a filter pass an object with properties size the blur amount in pixels and power is the strength. Lower powers is less spread on the blur.
// image must be loaded or created
var blurFilter = imageTools.createBlurConvolutionArray({size:17,power:1}); // size must be greater than 2 and must be odd eg 3,5,7,9...
// apply the convolution filter on the image. The returned image may be a new
//image if the input image does not have a ctx property pointing to a 2d canvas context
image = imageTools.applyConvolutionFilter(image,blurFilter);
In the demo I create a image, draw a circle on it, copy it and pad it so that there is room for the blur. Then create a blur filter and apply it to the image.
When I render the particles I first draw all the unblurred images, then draw the blurred copies with the ctx.globalCompositeOperation = "screen"; so that they have a shine. To vary the amount of shine I use the ctx.globalAlpha to vary the intensity of the rendered blurred image. To improve the FX I have drawn the blur image twice, once with oscillating scale and next at fixed scale and alpha.
The demo is simple, image tools can be found at the top. Then there is some stuff to setup the canvas and handle resize event. Then there is the code that creates the images, and apply the filters. Then starts the render adds some particles and renders everything.
Look in the function drawParticles for how I draw everything.
imageTools has all the image functions you will need. The imageTools.applyConvolutionFilter will apply any filter (sharpen, outline, and many more) you just need to create the appropriate filter. The apply uses the photon count colour model so gives a very high quality result especially for blurs type effects. (though for sharpen you may want to get in and change the squaring of the RGB values, I personally like it other do not)
The blur filter is not fast so if you apply it to larger images It would be best that you break it up in so you do not block the page execution.
A cheap way to get a blur is to copy the image to blur to a smaller version of itself, eg 1/4 then render it scaled back to normal size, the canvas will apply bilinear filtering on the image give a blur effect. Not the best quality but for most situations it is indistinguishable from the more sophisticated blur that I have presented.
UPDATE
Change the code so that the particles have a bit of a 3dFX to show that the blur can work up to larger scales. The blue particles are 32 by 32 image and the blur is 9 pixels with the blur image being 50by 50 pixels.
var imageTools = (function () {
var tools = {
canvas : function (width, height) { // create a blank image (canvas)
var c = document.createElement("canvas");
c.width = width;
c.height = height;
return c;
},
createImage : function (width, height) {
var image = this.canvas(width, height);
image.ctx = image.getContext("2d");
return image;
},
image2Canvas : function (img) {
var image = this.canvas(img.width, img.height);
image.ctx = image.getContext("2d");
image.drawImage(img, 0, 0);
return image;
},
padImage : function(img,amount){
var image = this.canvas(img.width + amount * 2, img.height + amount * 2);
image.ctx = image.getContext("2d");
image.ctx.drawImage(img, amount, amount);
return image;
},
getImageData : function (image) {
return (image.ctx || (this.image2Canvas(image).ctx)).getImageData(0, 0, image.width, image.height);
},
putImageData : function (image, imgData){
(image.ctx || (this.image2Canvas(image).ctx)).putImageData(imgData,0, 0);
return image;
},
createBlurConvolutionArray : function(options){
var i, j, d; // misc vars
var filterArray = []; // the array to create
var size = options.size === undefined ? 3: options.size; // array size
var center = Math.floor(size / 2); // center of array
// the power ? needs descriptive UI options
var power = options.power === undefined ? 1: options.power;
// dist to corner
var maxDist = Math.sqrt(center * center + center * center);
var dist = 0; // distance sum
var sum = 0; // weight sum
var centerWeight; // center calculated weight
var totalDistance; // calculated total distance from center
// first pass get the total distance
for(i = 0; i < size; i++){
for(j = 0; j < size; j++){
d = (maxDist-Math.sqrt((center-i)*(center-i)+(center-j)*(center-j)));
d = Math.pow(d,power)
dist += d;
}
}
totalDistance = dist; // total distance to all points;
// second pass get the total weight of all but center
for(i = 0; i < size; i++){
for(j = 0; j < size; j++){
d = (maxDist-Math.sqrt((center-i)*(center-i)+(center-j)*(center-j)));
d = Math.pow(d,power)
d = d/totalDistance;
sum += d;
}
}
var scale = 1/sum;
sum = 0; // used to check
for(i = 0; i < size; i++){
for(j = 0; j < size; j++){
d = (maxDist-Math.sqrt((center-i)*(center-i)+(center-j)*(center-j)));
d = Math.pow(d,power)
d = d/totalDistance;
filterArray.push(d*scale);
}
}
return filterArray;
},
applyConvolutionFilter : function(image,filter){
imageData = this.getImageData(image);
imageDataResult = this.getImageData(image);
var w = imageData.width;
var h = imageData.height;
var data = imageData.data;
var data1 = imageDataResult.data;
var side = Math.round(Math.sqrt(filter.length));
var halfSide = Math.floor(side/2);
var r,g,b,a,c;
for(var y = 0; y < h; y++){
for(var x = 0; x < w; x++){
var ind = y*4*w+x*4;
r = 0;
g = 0;
b = 0;
a = 0;
for (var cy=0; cy<side; cy++) {
for (var cx=0; cx<side; cx++) {
var scy = y + cy - halfSide;
var scx = x + cx - halfSide;
if (scy >= 0 && scy < h && scx >= 0 && scx < w) {
var srcOff = (scy*w+scx)*4;
var wt = filter[cy*side+cx];
r += data[srcOff+0] * data[srcOff+0] * wt;
g += data[srcOff+1] * data[srcOff+1] * wt;
b += data[srcOff+2] * data[srcOff+2] * wt;
a += data[srcOff+3] * data[srcOff+3] * wt;
}
}
}
data1[ind+0] = Math.sqrt(Math.max(0,r));
data1[ind+1] = Math.sqrt(Math.max(0,g));
data1[ind+2] = Math.sqrt(Math.max(0,b));
data1[ind+3] = Math.sqrt(Math.max(0,a));
}
}
return this.putImageData(image,imageDataResult);
}
};
return tools;
})();
/** SimpleFullCanvasMouse.js begin **/
const CANVAS_ELEMENT_ID = "canv";
const U = undefined;
var w, h, cw, ch; // short cut vars
var canvas, ctx;
var globalTime = 0;
var createCanvas, resizeCanvas, setGlobals;
var L = typeof log === "function" ? log : function(d){ console.log(d); }
createCanvas = function () {
var c,cs;
cs = (c = document.createElement("canvas")).style;
c.id = CANVAS_ELEMENT_ID;
cs.position = "absolute";
cs.top = cs.left = "0px";
cs.zIndex = 1000;
document.body.appendChild(c);
return c;
}
resizeCanvas = function () {
if (canvas === U) { canvas = createCanvas(); }
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx = canvas.getContext("2d");
if (typeof setGlobals === "function") { setGlobals(); }
}
setGlobals = function(){
cw = (w = canvas.width) / 2; ch = (h = canvas.height) / 2;
if(particles && particles.length > 0){
particles.length = 0;
}
}
resizeCanvas(); // create and size canvas
window.addEventListener("resize",resizeCanvas); // add resize event
const IMAGE_SIZE = 32;
const IMAGE_SIZE_HALF = 16;
const GRAV = 2001;
const NUM_PARTICLES = 90;
var background = imageTools.createImage(8,8);
var grad = ctx.createLinearGradient(0,0,0,8);
grad.addColorStop(0,"#000");
grad.addColorStop(1,"#048");
background.ctx.fillStyle = grad;
background.ctx.fillRect(0,0,8,8);
var circle = imageTools.createImage(IMAGE_SIZE,IMAGE_SIZE);
circle.ctx.fillStyle = "#5BF";
circle.ctx.arc(IMAGE_SIZE_HALF, IMAGE_SIZE_HALF, IMAGE_SIZE_HALF -2,0, Math.PI * 2);
circle.ctx.fill();
var blurFilter = imageTools.createBlurConvolutionArray({size:9,power:1}); // size must be greater than 2 and must be odd eg 3,5,7,9...
var blurCircle = imageTools.padImage(circle,9);
blurCircle = imageTools.applyConvolutionFilter(blurCircle,blurFilter)
var sun = imageTools.createImage(64,64);
grad = ctx.createRadialGradient(32,32,0,32,32,32);
grad.addColorStop(0,"#FF0");
grad.addColorStop(1,"#A40");
sun.ctx.fillStyle = grad;
sun.ctx.arc(32,32,32 -2,0, Math.PI * 2);
sun.ctx.fill();
var sunBlur = imageTools.padImage(sun,17);
blurFilter = imageTools.createBlurConvolutionArray({size:17,power:1}); // size must be greater than 2 and must be odd eg 3,5,7,9...
sunBlur = imageTools.applyConvolutionFilter(sunBlur,blurFilter);
var particles = [];
var createParticle = function(x,y,dx,dy){
var dir = Math.atan2(y-ch,x-cw);
var dist = Math.sqrt(Math.pow(y-ch,2)+Math.pow(x-cw,2));
var v = Math.sqrt(GRAV / dist); // get apporox orbital speed
return {
x : x,
y : y,
dx : dx + Math.cos(dir + Math.PI/2) * v, // set orbit speed at tangent
dy : dy + Math.sin(dir + Math.PI/2) * v,
s : (Math.random() + Math.random() + Math.random())/4 + 0.5, // scale
v : (Math.random() + Math.random() + Math.random()) / 3 + 2, // glow vary rate
};
}
var depthSort = function(a,b){
return b.y - a.y;
}
var updateParticles = function(){
var i,p,f,dist,dir;
for(i = 0; i < particles.length; i ++){
p = particles[i];
dist = Math.sqrt(Math.pow(cw-p.x,2)+Math.pow(ch-p.y,2));
dir = Math.atan2(ch-p.y,cw-p.x);
f = GRAV * 1 / (dist * dist);
p.dx += Math.cos(dir) * f;
p.dy += Math.sin(dir) * f;
p.x += p.dx;
p.y += p.dy;
p.rx = ((p.x - cw ) / (p.y + h)) * h + cw;
p.ry = ((p.y - ch ) / (p.y + h)) * h * -0.051+ ch;
//p.ry = ((h-p.y) - ch) * 0.1 + ch;
p.rs = (p.s / (p.y + h)) * h
}
particles.sort(depthSort)
}
var drawParticles = function(){
var i,j,p,f,dist,dir;
// draw behind the sun
for(i = 0; i < particles.length; i ++){
p = particles[i];
if(p.y - ch < 0){
break;
}
ctx.setTransform(p.rs,0,0,p.rs,p.rx,p.ry);
ctx.drawImage(circle,-IMAGE_SIZE_HALF,-IMAGE_SIZE_HALF);
}
// draw glow for behind the sun
ctx.globalCompositeOperation = "screen";
var iw = -blurCircle.width/2;
for(j = 0; j < i; j ++){
p = particles[j];
ctx.globalAlpha = ((Math.sin(globalTime / (50 * p.v)) + 1) / 2) * 0.6 + 0.4;
var scale = (1-(Math.sin(globalTime / (50 * p.v)) + 1) / 2) * 0.6 + 0.6;
ctx.setTransform(p.rs * 1.5 * scale,0,0,p.rs * 1.5* scale,p.rx,p.ry);
ctx.drawImage(blurCircle,iw,iw);
// second pass to intensify the glow
ctx.globalAlpha = 0.7;
ctx.setTransform(p.rs * 1.1,0,0,p.rs * 1.1,p.rx,p.ry);
ctx.drawImage(blurCircle,iw,iw);
}
// draw the sun
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 1;
ctx.setTransform(1,0,0,1,cw,ch);
ctx.drawImage(sun,-sun.width/2,-sun.height/2);
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = "screen";
ctx.setTransform(1,0,0,1,cw,ch);
ctx.drawImage(sunBlur,-sunBlur.width/2,-sunBlur.height/2);
var scale = Math.sin(globalTime / 100) *0.5 + 1;
ctx.globalAlpha = (Math.cos(globalTime / 100) + 1) * 0.2 + 0.4;;
ctx.setTransform(1 + scale,0,0,1 + scale,cw,ch);
ctx.drawImage(sunBlur,-sunBlur.width/2,-sunBlur.height/2);
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = "source-over";
// draw in front the sun
for(j = i; j < particles.length; j ++){
p = particles[j];
if(p.y > -h){ // don't draw past the near view plane
ctx.setTransform(p.rs,0,0,p.rs,p.rx,p.ry);
ctx.drawImage(circle,-IMAGE_SIZE_HALF,-IMAGE_SIZE_HALF);
}
}
ctx.globalCompositeOperation = "screen";
var iw = -blurCircle.width/2;
for(j = i; j < particles.length; j ++){
p = particles[j];
if(p.y > -h){ // don't draw past the near view plane
ctx.globalAlpha = ((Math.sin(globalTime / (50 * p.v)) + 1) / 2) * 0.6 + 0.4;
var scale = (1-(Math.sin(globalTime / (50 * p.v)) + 1) / 2) * 0.6 + 0.6;
ctx.setTransform(p.rs * 1.5 * scale,0,0,p.rs * 1.5* scale,p.rx,p.ry);
ctx.drawImage(blurCircle,iw,iw);
// second pass to intensify the glow
ctx.globalAlpha = 0.7;
ctx.setTransform(p.rs * 1.1,0,0,p.rs * 1.1,p.rx,p.ry);
ctx.drawImage(blurCircle,iw,iw);
}
}
ctx.globalCompositeOperation = "source-over";
}
var addParticles = function(count){
var ww = (h-10)* 2;
var cx = cw - ww/2;
var cy = ch - ww/2;
for(var i = 0; i < count; i ++){
particles.push(createParticle(cx + Math.random() * ww,cy + Math.random() * ww, Math.random() - 0.5, Math.random() - 0.5));
}
}
function display(){ // put code in here
if(particles.length === 0){
addParticles(NUM_PARTICLES);
}
ctx.setTransform(1,0,0,1,0,0); // reset transform
ctx.globalAlpha = 1; // reset alpha
ctx.drawImage(background,0,0,w,h)
updateParticles();
drawParticles();
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = "source-over";
}
function update(timer){ // Main update loop
globalTime = timer;
display(); // call demo code
requestAnimationFrame(update);
}
requestAnimationFrame(update);
/** SimpleFullCanvasMouse.js end **/

How to create a camera view in canvas that will follow a players rotation and rotation?

I'm trying to create a game in canvas with javascript where you control a spaceship and have it so that the canvas will translate and rotate to make it appear like the spaceship is staying stationary and not rotating.
Any help would be greatly appreciated.
window.addEventListener("load",eventWindowLoaded, false);
function eventWindowLoaded() {
canvasApp();
}
function canvasSupport() {
return Modernizr.canvas;
}
function canvasApp() {
if (!canvasSupport()) {
return;
}
var theCanvas = document.getElementById("myCanvas");
var height = theCanvas.height; //get the heigth of the canvas
var width = theCanvas.width; //get the width of the canvas
var context = theCanvas.getContext("2d"); //get the context
var then = Date.now();
var bgImage = new Image();
var stars = new Array;
bgImage.onload = function() {
context.translate(width/2,height/2);
main();
}
var rocket = {
xLoc: 0,
yLoc: 0,
score : 0,
damage : 0,
speed : 20,
angle : 0,
rotSpeed : 1,
rotChange: 0,
pointX: 0,
pointY: 0,
setScore : function(newScore){
this.score = newScore;
}
}
function Star(){
var dLoc = 100;
this.xLoc = rocket.pointX+ dLoc - Math.random()*2*dLoc;
this.yLoc = rocket.pointY + dLoc - Math.random()*2*dLoc;
//console.log(rocket.xLoc+" "+rocket.yLoc);
this.draw = function(){
drawStar(this.xLoc,this.yLoc,20,5,.5);
}
}
//var stars = new Array;
var drawStars = function(){
context.fillStyle = "yellow";
if (typeof stars !== 'undefined'){
//console.log("working");
for(var i=0;i< stars.length ;i++){
stars[i].draw();
}
}
}
var getDistance = function(x1,y1,x2,y2){
var distance = Math.sqrt(Math.pow((x2-x1),2)+Math.pow((y2-y1),2));
return distance;
}
var updateStars = function(){
var numStars = 10;
while(stars.length<numStars){
stars[stars.length] = new Star();
}
for(var i=0; i<stars.length; i++){
var tempDist = getDistance(rocket.pointX,rocket.pointY,stars[i].xLoc,stars[i].yLoc);
if(i == 0){
//console.log(tempDist);
}
if(tempDist > 100){
stars[i] = new Star();
}
}
}
function drawRocket(xLoc,yLoc, rWidth, rHeight){
var angle = rocket.angle;
var xVals = [xLoc,xLoc+(rWidth/2),xLoc+(rWidth/2),xLoc-(rWidth/2),xLoc-(rWidth/2),xLoc];
var yVals = [yLoc,yLoc+(rHeight/3),yLoc+rHeight,yLoc+rHeight,yLoc+(rHeight/3),yLoc];
for(var i = 0; i < xVals.length; i++){
xVals[i] -= xLoc;
yVals[i] -= yLoc+rHeight;
if(i == 0){
console.log(yVals[i]);
}
var tempXVal = xVals[i]*Math.cos(angle) - yVals[i]*Math.sin(angle);
var tempYVal = xVals[i]*Math.sin(angle) + yVals[i]*Math.cos(angle);
xVals[i] = tempXVal + xLoc;
yVals[i] = tempYVal+(yLoc+rHeight);
}
rocket.pointX = xVals[0];
rocket.pointY = yVals[0];
//rocket.yLoc = yVals[0];
//next rotate
context.beginPath();
context.moveTo(xVals[0],yVals[0])
for(var i = 1; i < xVals.length; i++){
context.lineTo(xVals[i],yVals[i]);
}
context.closePath();
context.lineWidth = 5;
context.strokeStyle = 'blue';
context.stroke();
}
var world = {
//pixels per second
startTime: Date.now(),
speed: 50,
startX:width/2,
startY:height/2,
originX: 0,
originY: 0,
xDist: 0,
yDist: 0,
rotationSpeed: 20,
angle: 0,
distance: 0,
calcOrigins : function(){
world.originX = -world.distance*Math.sin(world.angle*Math.PI/180);
world.originY = -world.distance*Math.cos(world.angle*Math.PI/180);
}
};
var keysDown = {};
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
}, false);
var update = function(modifier) {
if (37 in keysDown) { // Player holding left
rocket.angle -= rocket.rotSpeed* modifier;
rocket.rotChange = - rocket.rotSpeed* modifier;
//console.log("left");
}
if (39 in keysDown) { // Player holding right
rocket.angle += rocket.rotSpeed* modifier;
rocket.rotChange = rocket.rotSpeed* modifier;
//console.log("right");
}
};
var render = function (modifier) {
context.clearRect(-width*10,-height*10,width*20,height*20);
var dX = (rocket.speed*modifier)*Math.sin(rocket.angle);
var dY = (rocket.speed*modifier)*Math.cos(rocket.angle);
rocket.xLoc += dX;
rocket.yLoc -= dY;
updateStars();
drawStars();
context.translate(-dX,dY);
context.save();
context.translate(-rocket.pointX,-rocket.pointY);
context.translate(rocket.pointX,rocket.pointY);
drawRocket(rocket.xLoc,rocket.yLoc,50,200);
context.fillStyle = "red";
context.fillRect(rocket.pointX,rocket.pointY,15,5);
//context.restore(); // restores the coordinate system back to (0,0)
context.fillStyle = "green";
context.fillRect(0,0,10,10);
context.rotate(rocket.angle);
context.restore();
};
function drawStar(x, y, r, p, m)
{
context.save();
context.beginPath();
context.translate(x, y);
context.moveTo(0,0-r);
for (var i = 0; i < p; i++)
{
context.rotate(Math.PI / p);
context.lineTo(0, 0 - (r*m));
context.rotate(Math.PI / p);
context.lineTo(0, 0 - r);
}
context.fill();
context.restore();
}
// the game loop
function main(){
requestAnimationFrame(main);
var now = Date.now();
var delta = now - then;
update(delta / 1000);
//now = Date.now();
//delta = now - then;
render(delta / 1000);
then = now;
// Request to do this again ASAP
}
var w = window;
var requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
//start the game loop
//gameLoop();
//event listenters
bgImage.src = "images/background.jpg";
} //canvasApp()
Origin
When you need to rotate something in canvas it will always rotate around origin, or center for the grid if you like where the x and y axis crosses.
You may find my answer here useful as well
By default the origin is in the top left corner at (0, 0) in the bitmap.
So in order to rotate content around a (x,y) point the origin must first be translated to that point, then rotated and finally (and usually) translated back. Now things can be drawn in the normal order and they will all be drawn rotated relative to that rotation point:
ctx.translate(rotateCenterX, rotateCenterY);
ctx.rotate(angleInRadians);
ctx.translate(-rotateCenterX, -rotateCenterY);
Absolute angles and positions
Sometimes it's easier to keep track if an absolute angle is used rather than using an angle that you accumulate over time.
translate(), transform(), rotate() etc. are accumulative methods; they add to the previous transform. We can set absolute transforms using setTransform() (the last two arguments are for translation):
ctx.setTransform(1, 0, 0, 1, rotateCenterX, rotateCenterY); // absolute
ctx.rotate(absoluteAngleInRadians);
ctx.translate(-rotateCenterX, -rotateCenterY);
The rotateCenterX/Y will represent the position of the ship which is drawn untransformed. Also here absolute transforms can be a better choice as you can do the rotation using absolute angles, draw background, reset transformations and then draw in the ship at rotateCenterX/Y:
ctx.setTransform(1, 0, 0, 1, rotateCenterX, rotateCenterY);
ctx.rotate(absoluteAngleInRadians);
ctx.translate(-rotateCenterX, -rotateCenterY);
// update scene/background etc.
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transforms
ctx.drawImage(ship, rotateCenterX, rotateCenterY);
(Depending on orders of things you could replace the first line here with just translate() as the transforms are reset later, see demo for example).
This allows you to move the ship around without worrying about current transforms, when a rotation is needed use the ship's current position as center for translation and rotation.
And a final note: the angle you would use for rotation would of course be the counter-angle that should be represented (ie. ctx.rotate(-angle);).
Space demo ("random" movements and rotations)
The red "meteors" are dropping in one direction (from top), but as the ship "navigates" around they will change direction relative to our top view angle. Camera will be fixed on the ship's position.
(ignore the messy part - it's just for the demo setup, and I hate scrollbars... focus on the center part :) )
var img = new Image();
img.onload = function() {
var ctx = document.querySelector("canvas").getContext("2d"),
w = 600, h = 400, meteors = [], count = 35, i = 0, x = w * 0.5, y, a = 0, a2 = 0;
ctx.canvas.width = w; ctx.canvas.height = h; ctx.fillStyle = "#555";
while(i++ < count) meteors.push(new Meteor());
(function loop() {
ctx.clearRect(0, 0, w, h);
y = h * 0.5 + 30 + Math.sin((a+=0.01) % Math.PI*2) * 60; // ship's y and origin's y
// translate to center of ship, rotate, translate back, render bg, reset, draw ship
ctx.translate(x, y); // translate to origin
ctx.rotate(Math.sin((a2+=0.005) % Math.PI) - Math.PI*0.25); // rotate some angle
ctx.translate(-x, -y); // translate back
ctx.beginPath(); // render some moving meteors for the demo
for(var i = 0; i < count; i++) meteors[i].update(ctx); ctx.fill();
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transforms
ctx.drawImage(img, x - 32, y); // draw ship as normal
requestAnimationFrame(loop); // loop animation
})();
};
function Meteor() { // just some moving object..
var size = 5 + 35 * Math.random(), x = Math.random() * 600, y = -200;
this.update = function(ctx) {
ctx.moveTo(x + size, y); ctx.arc(x, y, size, 0, 6.28);
y += size * 0.5; if (y > 600) y = -200;
};
}
img.src = "http://i.imgur.com/67KQykW.png?1";
body {background:#333} canvas {background:#000}
<canvas></canvas>

Categories

Resources