I'm trying to draw an ellipse between two points. So far, I have it mostly working by adding the angle of the line to the theta of the circle function, but the issue comes with setting the ellipse height (ellipse_h below, controlled by the height slider).
Can anyone please help me rotate the ellipse height? Thank you!
const height_slider = document.getElementById("height_slider");
const height_readout = document.getElementById("height_readout");
const x1_slider = document.getElementById("x1_slider");
const x1_readout = document.getElementById("x1_readout");
const y1_slider = document.getElementById("y1_slider");
const y1_readout = document.getElementById("y1_readout");
const x2_slider = document.getElementById("x2_slider");
const x2_readout = document.getElementById("x2_readout");
const y2_slider = document.getElementById("y2_slider");
const y2_readout = document.getElementById("y2_readout");
const reset = document.getElementById("reset");
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext('2d');
function distance(x1, y1, x2, y2)
{
// Calculating distance
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) * 1.0);
}
function midpoint(x1, y1, x2, y2)
{
return [(x1 + x2) / 2,(y1 + y2) / 2];
}
function angle(x1, y1, x2, y2)
{
//radians
return Math.atan2(y2 - y1, x2 - x1);
}
//https://www.mathopenref.com/coordcirclealgorithm.html
function draw_circle()
{
let x1 = parseFloat(x1_slider.value);
let y1 = parseFloat(y1_slider.value);
let x2 = parseFloat(x2_slider.value);
let y2 = parseFloat(y2_slider.value);
var p1 = [x1,y1];
var p2 = [x2,y2];
var mid = midpoint(p1[0], p1[1], p2[0], p2[1]);
var step = 2*Math.PI/20;
var cx = mid[0];
var cy = mid[1];
var r = distance(p1[0], p1[1], p2[0], p2[1]) * 0.5;
var ellipse_h = parseFloat(height_slider.value);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
var deg = angle(x1, y1, x2, y2);
var cos = Math.cos(deg * Math.PI /180);
var sin = Math.sin(deg * Math.PI /180);
for(var theta=0; theta <= Math.PI; theta+=step)
{
var x = cx + r*Math.cos(theta-deg);
var y = cy - ellipse_h * r*Math.sin(theta-deg);
ctx.lineTo(x,y);
}
ctx.strokeStyle = "#22FF00";
ctx.stroke();
ctx.beginPath();
ctx.arc(p1[0], p1[1], 3, 0, 2 * Math.PI);
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(p2[0], p2[1], 3, 0, 2 * Math.PI);
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
x1_readout.innerText = Math.ceil(x1_slider.value*100)/100;
x2_readout.innerText = Math.ceil(x2_slider.value*100)/100;
y1_readout.innerText = Math.ceil(y1_slider.value*100)/100;
y2_readout.innerText = Math.ceil(y2_slider.value*100)/100;
height_readout.innerText = Math.ceil(ellipse_h*100)/100;
}
const default_x1 = 100;
const default_y1 = 150;
const default_x2 = 200;
const default_y2 = 150;
const default_height = 1;
function reset_defaults()
{
x1_slider.value = default_x1;
y1_slider.value = default_y1;
x2_slider.value = default_x2;
y2_slider.value = default_y2;
height_slider.value = default_height;
draw_circle();
}
x1_slider.oninput = draw_circle;
x2_slider.oninput = draw_circle;
y1_slider.oninput = draw_circle;
y2_slider.oninput = draw_circle;
height_slider.oninput = draw_circle;
reset.onclick = reset_defaults;
reset_defaults();
#canvas
{
width: 300px;
height: 300px;
border: 1px solid grey;
background-color: #272727;
}
#controls
{
font-family: Arial, sans;
font-size: 0.5em;
display: inline-flex;
border: 1px solid grey;
vertical-align: top;
padding: 8px;
width: 120px;
flex-direction: column;
justify-content: center;
align-items: center;
}
.control
{
display: inline-block;
}
h4
{
font-size: 1.3em;
margin: 0;
}
.control input
{
width: 40px;
}
#height,#reset
{
display: block;
margin-top: 10px;
}
<canvas id="canvas" width="300" height="300"></canvas>
<div id="controls">
<h4>Point 1</h4>
<div class="control">
<input type="range" min="0.001" max="300" step="0.001" value="100" id="x1_slider">X1:<text id="x1_readout" style="inline">100</text>
</div>
<div class="control">
<input type="range" min="0.001" max="300" step="0.001" value="100" id="y1_slider">Y1:<text id="y1_readout" style="inline">100</text>
</div>
<h4>Point 2</h4>
<div class="control">
<input type="range" min="0.001" max="300" step="0.001" value="200" id="x2_slider">X2:<text id="x2_readout" style="inline">200</text>
</div>
<div class="control">
<input type="range" min="0.001" max="300" step="0.001" value="100" id="y2_slider">Y2:<text id="y2_readout" style="inline">100</text>
</div>
<div class="control" id="height">
<input type="range" min="-6.28318530718" max="6.28318530718" step="0.001" value="1" id="height_slider">Height:<text id="height_readout" style="inline">1</text>
</div>
<button id="reset">Reset</button>
</div>
Canvas provides a method to draw ellipse arcs, all you have to do identify the parameters on your ellipse.
Let the center be the midpoint between the two points, radiusX be the half the distance between the two points, and rotation the angle of the line connecting them. All you have to do is to set radiusY.
const height_slider = document.getElementById("height_slider");
const height_readout = document.getElementById("height_readout");
const x1_slider = document.getElementById("x1_slider");
const x1_readout = document.getElementById("x1_readout");
const y1_slider = document.getElementById("y1_slider");
const y1_readout = document.getElementById("y1_readout");
const x2_slider = document.getElementById("x2_slider");
const x2_readout = document.getElementById("x2_readout");
const y2_slider = document.getElementById("y2_slider");
const y2_readout = document.getElementById("y2_readout");
const reset = document.getElementById("reset");
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext('2d');
function distance(x1, y1, x2, y2)
{
// Calculating distance
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) * 1.0);
}
function midpoint(x1, y1, x2, y2)
{
return [(x1 + x2) / 2,(y1 + y2) / 2];
}
function angle(x1, y1, x2, y2)
{
//radians
return Math.atan2(y2 - y1, x2 - x1);
}
//https://www.mathopenref.com/coordcirclealgorithm.html
function draw_circle()
{
let x1 = parseFloat(x1_slider.value);
let y1 = parseFloat(y1_slider.value);
let x2 = parseFloat(x2_slider.value);
let y2 = parseFloat(y2_slider.value);
var p1 = [x1,y1];
var p2 = [x2,y2];
var mid = midpoint(p1[0], p1[1], p2[0], p2[1]);
var step = 2*Math.PI/20;
var cx = mid[0];
var cy = mid[1];
var r = distance(p1[0], p1[1], p2[0], p2[1]) * 0.5;
var ellipse_h = parseFloat(height_slider.value);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
/*var deg = angle(x1, y1, x2, y2);
var cos = Math.cos(deg * Math.PI /180);
var sin = Math.sin(deg * Math.PI /180);
for(var theta=0; theta <= Math.PI; theta+=step)
{
var x = cx + r*Math.cos(theta-deg);
var y = cy - ellipse_h * r*Math.sin(theta-deg);
ctx.lineTo(x,y);
}*/
ctx.ellipse(
// center
(x1 + x2)/2, (y1 + y2)/2,
// radiusX
Math.hypot(x2 - x1, y2 - y1) / 2,
// radiusY
Math.abs(ellipse_h),
// rotation
Math.atan2(y2 - y1, x2 - x1),
// start angle
ellipse_h >= 0 ? 0: -Math.PI,
// end angle
ellipse_h >= 0 ? Math.PI : 0
);
ctx.strokeStyle = "#22FF00";
ctx.stroke();
ctx.beginPath();
ctx.arc(p1[0], p1[1], 3, 0, 2 * Math.PI);
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(p2[0], p2[1], 3, 0, 2 * Math.PI);
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
x1_readout.innerText = Math.ceil(x1_slider.value*100)/100;
x2_readout.innerText = Math.ceil(x2_slider.value*100)/100;
y1_readout.innerText = Math.ceil(y1_slider.value*100)/100;
y2_readout.innerText = Math.ceil(y2_slider.value*100)/100;
height_readout.innerText = Math.ceil(ellipse_h*100)/100;
}
const default_x1 = 100;
const default_y1 = 150;
const default_x2 = 200;
const default_y2 = 150;
const default_height = 10;
function reset_defaults()
{
x1_slider.value = default_x1;
y1_slider.value = default_y1;
x2_slider.value = default_x2;
y2_slider.value = default_y2;
height_slider.value = default_height;
draw_circle();
}
x1_slider.oninput = draw_circle;
x2_slider.oninput = draw_circle;
y1_slider.oninput = draw_circle;
y2_slider.oninput = draw_circle;
height_slider.oninput = draw_circle;
reset.onclick = reset_defaults;
reset_defaults();
#canvas
{
width: 300px;
height: 300px;
border: 1px solid grey;
background-color: #272727;
}
#controls
{
font-family: Arial, sans;
font-size: 0.5em;
display: inline-flex;
border: 1px solid grey;
vertical-align: top;
padding: 8px;
width: 120px;
flex-direction: column;
justify-content: center;
align-items: center;
}
.control
{
display: inline-block;
}
h4
{
font-size: 1.3em;
margin: 0;
}
.control input
{
width: 40px;
}
#height,#reset
{
display: block;
margin-top: 10px;
}
<canvas id="canvas" width="300" height="300"></canvas>
<div id="controls">
<h4>Point 1</h4>
<div class="control">
<input type="range" min="0.001" max="300" step="0.001" value="100" id="x1_slider">X1:<text id="x1_readout" style="inline">100</text>
</div>
<div class="control">
<input type="range" min="0.001" max="300" step="0.001" value="100" id="y1_slider">Y1:<text id="y1_readout" style="inline">100</text>
</div>
<h4>Point 2</h4>
<div class="control">
<input type="range" min="0.001" max="300" step="0.001" value="200" id="x2_slider">X2:<text id="x2_readout" style="inline">200</text>
</div>
<div class="control">
<input type="range" min="0.001" max="300" step="0.001" value="100" id="y2_slider">Y2:<text id="y2_readout" style="inline">100</text>
</div>
<div class="control" id="height">
<input type="range" min="-200" max="200" step="0.001" value="10" id="height_slider">Height:<text id="height_readout" style="inline">1</text>
</div>
<button id="reset">Reset</button>
</div>
In order to use negative ellipse_h we have change the start and end angles.
Related
This is my codepen. I want to check if the divs are overlapping each other with jQuery. I wrote a code for that but it doesn't work with round boxes. it only works with squares and rectangles. how can I make it work with round divs?
const coordinates = (className) => {
const val = document.querySelector(className);
return {
y: val.offsetTop,
x: val.offsetLeft,
yh: val.offsetTop + val.offsetHeight,
xw: val.offsetLeft + val.offsetWidth,
}
}
const cm = coordinates(".circle.small");
const cl = coordinates(".circle.large");
const offset_x = cm.x < cl.x && cm.xw > cl.x;
const offset_xw = cm.x < cl.xw && cm.xw > cl.xw;
const offset_cx = cm.x < cl.xw && cm.xw < cl.xw;
const offset_cy = cm.y < cl.yh && cm.yh < cl.yh;
const offset_y = cm.y < cl.y && cm.yh > cl.y;
const offset_yh = cm.y < cl.yh && cm.yh > cl.yh;
const is_x = offset_x || offset_xw || offset_cx;
const is_y = offset_y || offset_yh || offset_cy;
console.log(is_x, is_y);
.circle {
width: var(--square);
height: var(--square);
background: var(--bg);
border-radius: 50%;
}
.parent {
margin-left: 5px;
}
.parent2 {
margin-left: 15px;
}
.small {
--square: 50px;
--bg: red;
margin-bottom: -5px;
}
.large {
--square: 100px;
--bg: green;
}
<div class="parent">
<div class="circle small"></div>
</div>
<div class="parent2">
<div class="circle large"></div>
</div>
Your logic to calculate the delta between circle positions isn't quite right. You need to get the X and Y from the centre of each circle, then work out if the hypotenuse calculated from those two points is less than half of the combined radii.
Here's a working example. Note that I only added jQuery/jQueryUI to make dragging the circles around easier for testing - neither of these libraries are required for production use.
let $label = $('.overlap-label span');
const hasOverlap = (x0, y0, r0, x1, y1, r1) => Math.hypot(x0 - x1, y0 - y1) <= r0 + r1;
const coordinates = (className) => {
const el = document.querySelector(className);
const rect = el.getBoundingClientRect();
const radius = el.offsetHeight / 2;
return {
y: rect.top + radius,
x: rect.left + radius,
r: radius
}
}
const checkForOverlap = () => {
const cm = coordinates(".circle.small");
const cl = coordinates(".circle.large");
$label.text(hasOverlap(cm.x, cm.y, cm.r, cl.x, cl.y, cl.r));
}
$('.parent').draggable().on('drag', checkForOverlap);
.circle {
width: var(--square);
height: var(--square);
background: var(--bg);
border-radius: 50%;
display: inline-block;
}
.parent {
display: inline-block;
}
.small {
--square: 50px;
--bg: red;
}
.large {
--square: 100px;
--bg: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/themes/base/jquery-ui.min.css" />
<div class="overlap-label">Circles are overlapping? <span>false</span></div>
<div class="parent">
<div class="circle small"></div>
</div>
<div class="parent">
<div class="circle large"></div>
</div>
l do believe to have an issue regarding an if statement that allows for the detection of where the canvas object, being the image that displays , should be located at within the canvas. There is a reproducible demo provided.
NOTE: I do want to KEEP the css alignment, canvasauto, and not remove it if possible.
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
var the_button = document.getElementById("the_button");
var the_background = document.getElementById("the_background");
var imageXpos = 500;
var imageYpos = 300;
var imageWidth = 110;
var imageHeight = 80;
var imagecheck_Xpos = canvas.width - imageXpos;
var imagecheck_Ypos = canvas.height - imageYpos;
window.onload = function() {
ctx.drawImage(the_background, 0, 0, canvas.width, canvas.height);
ctx.drawImage(the_button, imagecheck_Xpos, imagecheck_Ypos, imageWidth, imageHeight);
}
the_button_function = (event) => {
const {
x,
y
} = event;
/* l believe the issue is here */
if ((x >= imagecheck_Xpos && x < (imagecheck_Xpos + imageWidth)) &&
(y >= imagecheck_Ypos && y < (imagecheck_Ypos + imageHeight))) {
alert("<Button>")
}
}
canvas.addEventListener('click', (e) => the_button_function(e));
html,
body {
width: 100%;
height: 100%;
margin: 0px;
border: 0;
overflow: hidden;
display: block;
}
.canvasauto {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<html>
<canvas id="c" width="970" height="550" class="canvasauto"></canvas>
<img style="display: none;" id="the_button" src="https://i.imgur.com/wO7Wc2w.png" />
<img style="display: none;" id="the_background" src="https://img.freepik.com/free-photo/hand-painted-watercolor-background-with-sky-clouds-shape_24972-1095.jpg?size=626&ext=jpg" />
</html>
You're using x from the MouseEvent. This is an experimental feature which is an alias of clientX.
The clientX property gives the coordinates relative to the application's viewport.
You probably want offsetX, which is relative to (the padding edge of the) target node.
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
var the_button = document.getElementById("the_button");
var the_background = document.getElementById("the_background");
var imageXpos = 500;
var imageYpos = 300;
var imageWidth = 110;
var imageHeight = 80;
var imagecheck_Xpos = canvas.width - imageXpos;
var imagecheck_Ypos = canvas.height - imageYpos;
window.onload = function() {
ctx.drawImage(the_background, 0, 0, canvas.width, canvas.height);
ctx.drawImage(the_button, imagecheck_Xpos, imagecheck_Ypos, imageWidth, imageHeight);
}
the_button_function = (event) => {
const {
offsetX: x,
offsetY: y
} = event;
/* l believe the issue is here */
if ((x >= imagecheck_Xpos && x < (imagecheck_Xpos + imageWidth)) &&
(y >= imagecheck_Ypos && y < (imagecheck_Ypos + imageHeight))) {
alert("<Button>")
}
}
canvas.addEventListener('click', (e) => the_button_function(e));
html,
body {
width: 100%;
height: 100%;
margin: 0px;
border: 0;
overflow: hidden;
display: block;
}
.canvasauto {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<html>
<canvas id="c" width="970" height="550" class="canvasauto"></canvas>
<img style="display: none;" id="the_button" src="https://i.imgur.com/wO7Wc2w.png" />
<img style="display: none;" id="the_background" src="https://img.freepik.com/free-photo/hand-painted-watercolor-background-with-sky-clouds-shape_24972-1095.jpg?size=626&ext=jpg" />
</html>
I'm trying to make a game and I have the blocks spawning randomly in the grid in the one fixed row (for example row 5 [horizontally]). Every time I click the button I want the blocks to move from row 5 to row 4(vertically). And then I want the new random blocks to generate on row 5 and so on. How can I do this? Right now it only spawning the new blocks under the first row (on the row 6, then 7 and so on).
//Accessing canvas
var canvas = document.getElementById('grid');
var ctx = canvas.getContext('2d');
var w = ctx.canvas.width;
var h = ctx.canvas.height;
// Drawing grid
var drawingGrid = function() {
for (x = 0; x <= w; x += 60) {
for (y = 0; y <= h; y += 60) {
// Gray grid
ctx.globalCompositeOperation = 'destination-over';
ctx.strokeStyle = "#cccccc";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, h);
ctx.moveTo(0, y);
ctx.lineTo(w, y);
if (x % 240 === 0) {
// Black X-axis grid |
ctx.globalCompositeOperation = "source-over";
if (x === 0 || x === 480) {
ctx.lineWidth = 5;
} else {
ctx.lineWidth = 1;
}
// Middle vertical line
if (x === 240) {
// 0-480
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, 480);
ctx.strokeStyle = "#222831";
ctx.stroke();
// 480-560
ctx.beginPath();
ctx.moveTo(x, 480);
ctx.lineTo(x, 540);
ctx.strokeStyle = "#cccccc";
ctx.globalCompositeOperation = 'destination-over';
} else {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, h);
ctx.strokeStyle = "#222831";
}
} else if (y % 240 === 0 || y === 540) {
// Black Y-axis grid _
ctx.globalCompositeOperation = "source-over";
ctx.strokeStyle = "#222831";
if (y === 0 || y === 540) {
ctx.lineWidth = 5;
} else if (y === 480) {
ctx.lineWidth = 2.5;
} else {
ctx.lineWidth = 1;
}
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(h, y);
}
ctx.stroke();
}
}
};
drawingGrid(480, 540, 'grid');
// Starting coordinates
var posX = 0;
var posY = 240;
// Move blocks on Y axis
function moveY(){
posY +=60;
}
// Spawn random amount of blocks on the field
function gener(){
posX = 60*Math.floor(8*Math.random());
}
function spawnRandomObject() {
// Game Object
ctx.fillStyle = '#f2a365';
ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.fillRect(posX, posY, 60, 60);
ctx.stroke();
}
// Blocks moving up
document.getElementById("button").addEventListener("click", function(){
// Spawn random amount of objects
for (var i=0; i<Math.floor((Math.random()*8)+1)*2; i++){
gener();
spawnRandomObject();
}
moveY();
});
body{
background-color: #ececec;
}
canvas{
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
}
.row{
padding: 20px;
margin: 0;
}
.firstrow{
width:20%;
}
.mainrow{
width:60%;
display: block;
}
.thirdrow{
width: 20%;
}
.header{
background-color: #222831;
color: #ececec;
padding: 20px;
}
.container{
margin-top: 20px;
padding: 0px;
display: flex;
box-sizing: inherit;
}
.thirdrow{
text-align: right;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Shmetris</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!-- Local CSS -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Header -->
<div class="header">
<h1>Shmetris</h1>
</div>
<div class="container">
<!-- Controls -->
<div class="row first">
<div class="col">
<h1>Score: 0</h1>
<br>
<button type="button" class="btn btn-dark" id="button">Refresh</button>
</div>
</div>
<!-- Game Area -->
<div class="row mainrow">
<div class="col-" id="gamearea">
<!-- Canvas -->
<canvas id="grid" width="480" height="540" style="background: #ececec "></canvas>
</div>
</div>
<!-- -->
<div class="row thirdrow">
<div class="col" style="text-align:left;">
</div>
</div>
</div>
<!-- Script -->
<script src="app.js"></script>
</body>
</html>
I removed your moveY() function and added the moveRow() function. The game objects (the rects) are saved to a list objects. Their y position is increased on each button click. The old drawn positions are removed, the new positions are drawn. Then the randomly generated blocks are added in the 5th row.
Note that the clearRect() function inside the removeCell() also removes parts of the grid. This causes to redraw the grid every time. You can improve the code by splitting your grid creation in using a sub function which draws the grid on only one cell. Then you can redraw the grid only on those cells that are needed. This probably is a performance boost and makes the code more beautiful in my eyes, but it works like this too.
I also suggest to use length instead of 60 and calculate the thicker grid lines by the length, e.g. 8 * length instead of 480 and so on.
//Accessing canvas
var canvas = document.getElementById('grid');
var ctx = canvas.getContext('2d');
var w = ctx.canvas.width;
var h = ctx.canvas.height;
// Drawing grid
var drawingGrid = function() {
for (x = 0; x <= w; x += 60) {
for (y = 0; y <= h; y += 60) {
// Gray grid
ctx.globalCompositeOperation = 'destination-over';
ctx.strokeStyle = "#cccccc";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, h);
ctx.moveTo(0, y);
ctx.lineTo(w, y);
if (x % 240 === 0) {
// Black X-axis grid |
ctx.globalCompositeOperation = "source-over";
if (x === 0 || x === 480) {
ctx.lineWidth = 5;
} else {
ctx.lineWidth = 1;
}
// Middle vertical line
if (x === 240) {
// 0-480
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, 480);
ctx.strokeStyle = "#222831";
ctx.stroke();
// 480-560
ctx.beginPath();
ctx.moveTo(x, 480);
ctx.lineTo(x, 540);
ctx.strokeStyle = "#cccccc";
ctx.globalCompositeOperation = 'destination-over';
} else {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, h);
ctx.strokeStyle = "#222831";
}
} else if (y % 240 === 0 || y === 540) {
// Black Y-axis grid _
ctx.globalCompositeOperation = "source-over";
ctx.strokeStyle = "#222831";
if (y === 0 || y === 540) {
ctx.lineWidth = 5;
} else if (y === 480) {
ctx.lineWidth = 2.5;
} else {
ctx.lineWidth = 1;
}
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(h, y);
}
ctx.stroke();
}
}
};
drawingGrid(480, 540, 'grid');
var length = 60;
// Starting coordinates
var posX = 0;
var posY = 4 * length;
var objects = []
function moveRows(){
for(var i = 0; i < objects.length; i++){
// remove old objects
removeCell(objects[i][0], objects[i][1]);
// move objects
objects[i][1] += length;
}
drawingGrid();
for(var i = 0; i < objects.length; i++){
// redraw objects on new location
drawCell(objects[i][0], objects[i][1]);
}
}
// Spawn random amount of blocks on the field
function gener(){
posX = length*Math.floor(8*Math.random());
}
function spawnRandomObject() {
// Game Object
drawCell(posX, posY);
objects.push([posX, posY]);
}
function drawCell(x, y, color){
ctx.fillStyle = "#f2a365";
ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.fillRect(x, y, length, length);
ctx.stroke();
}
function removeCell(x, y){
ctx.clearRect(x, y, length, length);
}
// Blocks moving up
document.getElementById("button").addEventListener("click", function(){
// Spawn random amount of objects
moveRows();
for (var i=0; i<Math.floor((Math.random()*8)+1)*2; i++){
gener();
spawnRandomObject();
}
});
body{
background-color: #ececec;
}
canvas{
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
}
.row{
padding: 20px;
margin: 0;
}
.firstrow{
width:20%;
}
.mainrow{
width:60%;
display: block;
}
.thirdrow{
width: 20%;
}
.header{
background-color: #222831;
color: #ececec;
padding: 20px;
}
.container{
margin-top: 20px;
padding: 0px;
display: flex;
box-sizing: inherit;
}
.thirdrow{
text-align: right;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Shmetris</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!-- Local CSS -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Header -->
<div class="header">
<h1>Shmetris</h1>
</div>
<div class="container">
<!-- Controls -->
<div class="row first">
<div class="col">
<h1>Score: 0</h1>
<br>
<button type="button" class="btn btn-dark" id="button">Refresh</button>
</div>
</div>
<!-- Game Area -->
<div class="row mainrow">
<div class="col-" id="gamearea">
<!-- Canvas -->
<canvas id="grid" width="480" height="540" style="background: #ececec "></canvas>
</div>
</div>
<!-- -->
<div class="row thirdrow">
<div class="col" style="text-align:left;">
</div>
</div>
</div>
<!-- Script -->
<script src="app.js"></script>
</body>
</html>
I am extremely new to creating extensions for chrome, and right now I'm just trying to mess around and create a simple canvas that you can open up and draw on.
When I load popup.html as a normal webpage everything seems to work just fine, but when I open the extension in chrome there is no functionality.
Manifest:
{
"manifest_version": 2,
"name": "Sketchpad",
"description": " ",
"version": "0.1",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
}
}
HTML:
<!doctype html>
<html>
<head>
<title>Drawing Pad</title>
<style>
body {
font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif;
font-size: 100%;
}
.color {display: inline-block;}
#can {
cursor: url(pencil.png), auto;
}
</style>
<script src="canvas.js"></script>
</head>
<body onload="init()">
<canvas id="can" width="400" height="400" style="border:2px solid;"></canvas><br>
<div style="display: inline-block;">Choose Color
<div class="color" style="width: 10px; height: 10px; background: green;" id="green" onclick="color(this)"></div>
<div class="color" style="width: 10px; height: 10px; background: blue;" id="blue" onclick="color(this)"></div>
<div class="color" style="width: 10px; height: 10px; background: red;" id="red" onclick="color(this)"></div>
<div class="color" style="width: 10px; height: 10px; background: yellow;" id="yellow" onclick="color(this)"></div>
<div class="color" style="width: 10px; height: 10px; background: orange;" id="orange" onclick="color(this)"></div>
<div class="color" style="width: 10px; height: 10px; background: black;" id="black" onclick="color(this)"></div>
</div>
<div style="display: inline-block;">Eraser
<div style="width:15px;height:15px;background:white;border:2px solid;display: inline-block" id="white" onclick="color(this)"></div>
</div><br>
<input type="button" value="Clear" id="clr" size="23" onclick="erase()">
</body>
</html>
JS:
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "black",
y = 2;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
canvas.addEventListener("mousemove", function (e) {
findxy('move', e)
}, false);
canvas.addEventListener("mousedown", function (e) {
findxy('down', e)
}, false);
canvas.addEventListener("mouseup", function (e) {
findxy('up', e)
}, false);
canvas.addEventListener("mouseout", function (e) {
findxy('out', e)
}, false);
}
function color(obj) {
switch (obj.id) {
case "green":
x = "green";
break;
case "blue":
x = "blue";
break;
case "red":
x = "red";
break;
case "yellow":
x = "yellow";
break;
case "orange":
x = "orange";
break;
case "black":
x = "black";
break;
case "white":
x = "white";
break;
}
if (x == "white") y = 14;
else y = 2;
}
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
function erase() {
ctx.clearRect(0, 0, w, h);
}
function findxy(res, e) {
if (res == 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
flag = true;
dot_flag = true;
if (dot_flag) {
ctx.beginPath();
ctx.fillStyle = x;
ctx.fillRect(currX, currY, 2, 2);
ctx.closePath();
dot_flag = false;
}
}
if (res == 'up' || res == "out") {
flag = false;
}
if (res == 'move') {
if (flag) {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
draw();
}
}
}
After doing some research I have a feeling that something is wrong with the way I have my js code formatted, but I cannot pinpoint what that is. Sorry for the long post and thanks, any help is appreciated.
You can't put javascript code in html file in goolge-chrome-extension.
replace
html
<body onload="init()">
with:
js
document.body.addEventListener('load', function () {...})
For more information, see contentSecurityPolicy.
Also since inline JS is not allowed, onclick like <input type="button" value="Clear" id="clr" size="23" onclick="erase()"> should be
<input type="button" value="Clear" id="clr" size="23"> and use addEventListener to bind the event in your js file.
document.addEventListener('DOMContentLoaded', function() {
var clear = document.getElementById('clr');
clear.addEventListener('click', function() {
erase();
});
});
On my website, I want do render a <canvas> on top of a <div> with some other <div>'s in it. This is all working okay, however, drawing in the canvas is not possible, because it's positioned under the main <div>. You can test it in the codepen below. You can only draw on a small strip near the bottom.
Codepen: http://codepen.io/anon/pen/hfmBG
Code:
<html>
<head>
<script type="text/javascript">
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "#000",
y = 1;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
canvas.addEventListener("mousemove", function (e) {
findxy('move', e)
}, false);
canvas.addEventListener("mousedown", function (e) {
findxy('down', e)
}, false);
canvas.addEventListener("mouseup", function (e) {
findxy('up', e)
}, false);
canvas.addEventListener("mouseout", function (e) {
findxy('out', e)
}, false);
}
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
function erase() {
var m = confirm("Want to clear");
if (m) {
ctx.clearRect(0, 0, w, h);
document.getElementById("canvasimg").style.display = "none";
}
}
function findxy(res, e) {
if (res == 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
flag = true;
dot_flag = true;
if (dot_flag) {
ctx.beginPath();
ctx.fillStyle = x;
ctx.fillRect(currX, currY, 2, 2);
ctx.closePath();
dot_flag = false;
}
}
if (res == 'up' || res == "out") {
flag = false;
}
if (res == 'move') {
if (flag) {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
draw();
}
}
}
function print(){
var c = document.getElementById("can");
var ctx = c.getContext("2d");
var imgData = ctx.getImageData(10,10,50,50);
console.log(imgData);
}
</script>
<style>
.patternlockbutton{
border-color: red;
background-color: transparent;
background-repeat:no-repeat;
display:block;
width:33px;
height:33px;
float:left;
margin:26px;
z-index:1;
-ms-touch-action: none;
border-style: solid;
border-width: 5px;
-webkit-border-top-left-radius: 50px;
-webkit-border-top-right-radius: 50px;
-moz-border-radius-topleft: 50px;
-moz-border-radius-topright: 50px;
border-top-left-radius: 50px;
border-top-right-radius: 50px;
-webkit-border-bottom-left-radius: 50px;
-webkit-border-bottom-right-radius: 50px;
-moz-border-radius-bottomleft: 50px;
-moz-border-radius-bottomright: 50px;
border-bottom-left-radius: 50px;
border-bottom-right-radius: 50px;
}
#can {
z-index: 99;
display: block;
}
</style>
</head>
<body onload="init()">
<div style="width:300px;height:400px;">
<div class="patternlockbutton" id="patternlockbutton1"></div>
<div class="patternlockbutton" id="patternlockbutton2"></div>
<div class="patternlockbutton" id="patternlockbutton3"></div>
<div class="patternlockbutton" id="patternlockbutton4"></div>
<div class="patternlockbutton" id="patternlockbutton5"></div>
<div class="patternlockbutton" id="patternlockbutton6"></div>
<div class="patternlockbutton" id="patternlockbutton7"></div>
<div class="patternlockbutton" id="patternlockbutton8"></div>
<div class="patternlockbutton" id="patternlockbutton9"></div>
<canvas id="can" width="300px" height="400px"></canvas>
</div>
<input type="button" value="clear" id="clr" size="23" onclick="erase()" style="position:absolute;top:55%;left:15%;">
<button onclick="print()">Console.log</button>
</body>
</html>
If you want to position an HTML element on top of other elements, you should set its position: absolute in CSS.
In your case, the parent div of the canvas should have this style applied:
position: relative;
The canvas should have this style applied:
position: absolute;
top: 0;
left: 0;