Two layered canvas scaled to automatically fill flex column space - javascript

I'd like two left canvas (layered on top of each other), to fit the left column (100% width minus the right column's 300px width).
It should work even if the canvas' height and width change dynamically, see here after 1 second and 3 seconds, when the canvas width changes from 500 to 1500 pixels wide.
var c1 = document.getElementById("canvas1"), ctx1 = c1.getContext("2d");
var c2 = document.getElementById("canvas2"), ctx2 = c2.getContext("2d");
setTimeout(() => {
ctx1.canvas.width = 500;
ctx1.canvas.height = 300;
ctx1.rect(0, 0, 500, 300);
ctx1.fill();
ctx2.canvas.width = 500;
ctx2.canvas.height = 300;
ctx2.rect(50, 50, 100, 100);
ctx2.fillStyle = "green";
ctx2.fill();
}, 1000);
setTimeout(() => {
ctx1.canvas.width = 1500;
ctx1.canvas.height = 500;
ctx1.rect(0, 0, 1500, 500);
ctx1.fill();
ctx2.canvas.width = 1500;
ctx2.canvas.height = 500;
ctx2.rect(100, 100, 100, 100);
ctx2.fillStyle = "red";
ctx2.fill();
}, 3000);
.container { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; background-color: yellow; }
.column { border: 1px solid black; }
.canvas-wrapper { margin: 1rem; flex: 1; }
#canvas2 { position: absolute; top: 0; left: 0; }
.right-column { width: 300px; }
<div class="container">
<div class="canvas-wrapper column">
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
</div>
<div class="right-column column">
Hello world
</div>
</div>
Here is how it should look like, in both cases it should be rescaled to fit the left column.
In the second case (with the red square), the canvas should be scaled down to fit in the left column (for example to a width of ~1000px if the browser viewport width is 1300 px, minus the 300 px for the right column), even if the real canvas width is still 1500 px.
I have tried multiple variations of flexbox, without success.
If possible, I'd like to keep flex and avoid calc(100% - 300px) rules.
TL;DR: How to make two layered canvas of the same size on top of each other (this size can vary) fit automatically a column in a flex layout?

The trick with FlexBox is to make the left column have a min-width:0, this allows it to shrink, and your 300px right column can then stay the same.
Also you will want to make another div for you canvas-wrapper, so that margins etc work as expected.
Eg.
var c1 = document.getElementById("canvas1"), ctx1 = c1.getContext("2d");
var c2 = document.getElementById("canvas2"), ctx2 = c2.getContext("2d");
setTimeout(() => {
ctx1.canvas.width = 500;
ctx1.canvas.height = 300;
ctx1.rect(0, 0, 500, 300);
ctx1.fill();
ctx2.canvas.width = 500;
ctx2.canvas.height = 300;
ctx2.rect(50, 50, 100, 100);
ctx2.fillStyle = "green";
ctx2.fill();
}, 1000);
setTimeout(() => {
ctx1.canvas.width = 1500;
ctx1.canvas.height = 500;
ctx1.rect(0, 0, 1500, 500);
ctx1.fill();
ctx2.canvas.width = 1500;
ctx2.canvas.height = 500;
ctx2.rect(100, 100, 100, 100);
ctx2.fillStyle = "red";
ctx2.fill();
}, 3000);
.container {
display: flex;
align-items: center;
justify-content: center;
background-color: yellow;
}
.column {
border: 1px solid black;
}
.canvas-wrapper {
margin: 1rem;
flex: 1;
position: relative;
}
#canvas1 {
width: 100%;
}
#canvas2 {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.left-column {
min-width: 0;
}
.right-column {
width: 300px;
min-width: 300px;
}
<div class="container">
<div class="left-column column">
<div class="canvas-wrapper">
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
</div>
</div>
<div class="right-column column">
Hello world
</div>
</div>

Does changing to grid help?
This snippet has two columns in the grid, the first one taking what's left after the 300px column. The width and height of the canvases is set to maximum of the cell dimensions.
var c1 = document.getElementById("canvas1"),
ctx1 = c1.getContext("2d");
var c2 = document.getElementById("canvas2"),
ctx2 = c2.getContext("2d");
setTimeout(() => {
ctx1.canvas.width = 500;
ctx1.canvas.height = 300;
ctx1.rect(0, 0, 500, 300);
ctx1.fill();
ctx2.canvas.width = 500;
ctx2.canvas.height = 300;
ctx2.rect(50, 50, 100, 100);
ctx2.fillStyle = "green";
ctx2.fill();
}, 1000);
setTimeout(() => {
ctx1.canvas.width = 1500;
ctx1.canvas.height = 500;
ctx1.rect(0, 0, 1500, 500);
ctx1.fill();
ctx2.canvas.width = 1500;
ctx2.canvas.height = 500;
ctx2.rect(100, 100, 100, 100);
ctx2.fillStyle = "red";
ctx2.fill();
}, 3000);
.container {
display: grid;
grid-template-columns: 1fr 300px;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: yellow;
}
.column {
border: 1px solid black;
}
.canvas-wrapper {
margin: 1rem;
flex: 1;
}
#canvas2 {
position: absolute;
top: 0;
left: 0;
}
canvas {
max-width: 100%;
max-height: 100%;
}
.right-column {
width: 300px;
}
<div class="container">
<div class="canvas-wrapper column">
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
</div>
<div class="right-column column">
Hello world
</div>
</div>

Related

Javascript/HTML canvas: drawing on dynamically sized image

I'm trying to create an interface (HTML canvas/Vanilla JS) where a user can:
Upload an image
Draw on the image
Save the new image in the same resolution as the original from step (1)
I'm stuck on (2). The x and y coordinates are all wrong when I try to draw. How far off they are depends on the size/shape of the image uploaded. I have made a codepen to demonstrate, because the Stack code snippet below was behaving strangely when run.
I am a JS/HTML rookie but my hypothesis is that the incorrect coordinates are based on the image's original resolution (which is retained when I save the resultant image) and not the image's resolution as it is displayed in the canvas.
Any help much appreciated.
const fileInput = document.querySelector(".file-input"),
inputImg = document.querySelector(".input-img img"),
chooseImgBtn = document.querySelector(".choose-img"),
saveImgBtn = document.querySelector(".save-img");
drawOnImage();
fileInput.addEventListener("change", async(e) => {
const [file] = fileInput.files;
// displaying the uploaded image
const image = document.createElement("img");
image.src = await fileToDataUri(file);
// enbaling the brush after after the image
// has been uploaded
image.addEventListener("load", () => {
drawOnImage(image);
});
return false;
});
function fileToDataUri(field) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.addEventListener("load", () => {
resolve(reader.result);
});
reader.readAsDataURL(field);
});
}
const colorElement = document.getElementsByName("colorRadio");
let color;
colorElement.forEach((c) => {
if (c.checked) color = c.value;
});
colorElement.forEach((c) => {
c.onclick = () => {
color = c.value;
};
});
function drawOnImage(image = null) {
const canvasElement = document.getElementById("canvas");
const context = canvasElement.getContext("2d");
// if an image is present,
// the image passed as a parameter is drawn in the canvas
if (image) {
const imageWidth = image.width;
const imageHeight = image.height;
// rescaling the canvas element
canvasElement.width = imageWidth;
canvasElement.height = imageHeight;
context.drawImage(image, 0, 0, imageWidth, imageHeight);
}
let isDrawing;
canvasElement.onmousedown = (e) => {
isDrawing = true;
context.beginPath();
context.lineWidth = size;
context.strokeStyle = "black";
context.lineJoin = "round";
context.lineCap = "round";
context.moveTo(e.clientX, e.clientY);
};
canvasElement.onmousemove = (e) => {
if (isDrawing) {
context.lineTo(e.clientX, e.clientY);
context.stroke();
}
};
canvasElement.onmouseup = function() {
isDrawing = false;
context.closePath();
};
}
chooseImgBtn.addEventListener("click", () => fileInput.click());
/* Import Google font - Poppins */
#import url('https://fonts.googleapis.com/css2?family=Poppins:wght#400;500;600&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body {
display: flex;
padding: 10px;
min-height: 90vh;
align-items: center;
justify-content: center;
background: #9c9c9c;
}
.container {
width: 1200px;
padding: 30px 35px 35px;
background: #fff;
border-radius: 10px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.container .editor-panel,
.container .controls .reset-filter,
.container .controls .save-img {
opacity: 0.5;
pointer-events: none;
}
.container h2 {
margin-top: -8px;
font-size: 22px;
font-weight: 500;
}
.container .wrapper {
display: flex;
margin: 20px 0;
min-height: 335px;
}
.editor-panel .options,
.controls {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.wrapper .canvas-wrapper {
flex-grow: 1;
display: flex;
overflow: hidden;
margin-left: 20px;
border-radius: 5px;
align-items: center;
justify-content: center;
}
#canvas {
max-width: 700px;
max-height: 650px;
width: 100%;
height: 100%;
border-radius: 5px;
border: 1px solid #ccc;
object-fit: contain;
}
.controls button {
padding: 11px 20px;
font-size: 14px;
border-radius: 3px;
outline: none;
color: #fff;
cursor: pointer;
background: none;
transition: all 0.3s ease;
text-transform: uppercase;
}
.controls .choose-img {
background: #6C757D;
border: 1px solid #6C757D;
}
.controls .save-img {
margin-left: 5px;
background: #5372F0;
border: 1px solid #5372F0;
}
<link rel="stylesheet" href="https://unpkg.com/boxicons#2.1.2/css/boxicons.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" />
<div class="container">
<h2>Drawing</h2>
<div class="wrapper">
<div class="canvas-wrapper">
<canvas id="canvas" style="border: 1px solid black;"></canvas>
</div>
</div>
<div class="controls">
<input type="file" class="file-input" accept="image/*" hidden>
<button class="choose-img">Choose Input Image</button>
<div class="row">
<button class="save-img">Save</button>
</div>
</div>
</div>
You've got two separate problems here. The first is using clientX and clientY to get the mouse position. These are the X and Y coordinates relative to the viewport, such that (0, 0) is the top left corner of the browser window, not the canvas. You want to use offsetX and offsetY instead, which are relative to the element that triggered the event.
The second problem is using CSS to modify the size of the canvas (width: 100%; height: 100%). This changes the physical size of the element on the screen, but not the dimensions of the canvas context, which you set when uploading an image. For example, let's say you set canvas.width and canvas.height (the size of the canvas context) to be 200x100 and you set its CSS width and height to be 400x200. The element will be 400 pixels wide on your screen and if you place your mouse halfway across, the offsetX will be 200. However, drawing anything in the canvas context with an X of 200 will place it at the far right edge, because the context width is 200, not 400.
To deal with this, you either need to not change the canvas's size in CSS at all, or account for the difference in your JS by dividing the mouse's position by the ratio between the element's physical size and the canvas's context size.
Here's an example. The canvas is upscaled by 2x via CSS to be 400x200. The black rectangle is drawn using the exact position of the mouse, while the red rectangle divides down to get the correct corresponding position on the canvas.
const mouse = document.getElementById("mouse");
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
// 200x100 canvas size
canvas.width = 200;
canvas.height = 100;
canvas.addEventListener("mousemove", e => {
mouse.innerText = `mouse x: ${e.offsetX}`;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw at 1:1 physical size to canvas size
ctx.fillStyle = "#000";
ctx.fillRect(e.offsetX, e.offsetY, 20, 20);
// draw at 2:1 physical size to canvas size
ctx.fillStyle = "#f00";
ctx.fillRect(e.offsetX / 2, e.offsetY / 2, 20, 20);
// or if the ratio is not known:
const width_ratio = canvas.clientWidth / canvas.width;
const height_ratio = canvas.clientHeight / canvas.height;
ctx.fillRect(e.offsetX / width_ratio, e.offsetY / height_ratio, 20, 20);
});
#canvas {
width: 400px;
height: 200px;
border: 1px solid #000;
}
<div id="mouse"></div>
<canvas id="canvas"></canvas>

How can i touch multiple things at a time and not only one in html/javascript

So, I'm building a web that acts like a controller and then sends the data through websocket, i encounter a problem and after quick search on google doesn't help me. The problem is when i put my finger on the web it only register one finger at a time, so when i moving the joystick and then pressing the other button, the joystick will not be working until i release the new finger.
What i'm trying to ask is how can i touch multiple things at a time and not only one at a time
Here is the screenshot and the code
var canvas, ctx;
window.addEventListener('load', () => {
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
resize();
document.addEventListener('mousedown', startDrawing);
document.addEventListener('mouseup', stopDrawing);
document.addEventListener('mousemove', Draw);
document.addEventListener('touchstart', startDrawing);
document.addEventListener('touchend', stopDrawing);
document.addEventListener('touchcancel', stopDrawing);
document.addEventListener('touchmove', Draw);
window.addEventListener('resize', resize);
document.getElementById("x_coordinate").innerText = 0;
document.getElementById("y_coordinate").innerText = 0;
document.getElementById("speed").innerText = 0;
document.getElementById("angle").innerText = 0;
});
var width, height, radius, x_orig, y_orig;
function resize() {
width = 250;
radius = 50;
height = 250;
ctx.canvas.width = width;
ctx.canvas.height = height;
background();
joystick(width / 2, height / 3);
}
function background() {
x_orig = width / 2;
y_orig = height / 3;
ctx.beginPath();
ctx.arc(x_orig, y_orig, radius + 20, 0, Math.PI * 2, true);
ctx.fillStyle = '#ECE5E5';
ctx.fill();
}
function joystick(width, height) {
ctx.beginPath();
ctx.arc(width, height, radius, 0, Math.PI * 2, true);
ctx.fillStyle = '#F08080';
ctx.fill();
ctx.strokeStyle = '#F6ABAB';
ctx.lineWidth = 8;
ctx.stroke();
}
let coord = {
x: 0,
y: 0
};
let paint = false;
function getPosition(event) {
var mouse_x = event.clientX || event.touches[0].clientX;
var mouse_y = event.clientY || event.touches[0].clientY;
coord.x = mouse_x - canvas.offsetLeft;
coord.y = mouse_y - canvas.offsetTop;
}
function is_it_in_the_circle() {
var current_radius = Math.sqrt(Math.pow(coord.x - x_orig, 2) + Math.pow(coord.y - y_orig, 2));
if (radius >= current_radius) return true
else return false
}
function startDrawing(event) {
paint = true;
getPosition(event);
if (is_it_in_the_circle()) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
background();
joystick(coord.x, coord.y);
Draw();
}
}
function stopDrawing() {
paint = false;
ctx.clearRect(0, 0, canvas.width, canvas.height);
background();
joystick(width / 2, height / 3);
document.getElementById("x_coordinate").innerText = 0;
document.getElementById("y_coordinate").innerText = 0;
document.getElementById("speed").innerText = 0;
document.getElementById("angle").innerText = 0;
}
function Draw(event) {
if (paint) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
background();
var angle_in_degrees, x, y, speed;
var angle = Math.atan2((coord.y - y_orig), (coord.x - x_orig));
if (Math.sign(angle) == -1) {
angle_in_degrees = Math.round(-angle * 180 / Math.PI);
} else {
angle_in_degrees = Math.round(360 - angle * 180 / Math.PI);
}
if (is_it_in_the_circle()) {
joystick(coord.x, coord.y);
x = coord.x;
y = coord.y;
} else {
x = radius * Math.cos(angle) + x_orig;
y = radius * Math.sin(angle) + y_orig;
joystick(x, y);
}
getPosition(event);
var speed = Math.round(100 * Math.sqrt(Math.pow(x - x_orig, 2) + Math.pow(y - y_orig, 2)) / radius);
var x_relative = Math.round(x - x_orig);
var y_relative = Math.round(y - y_orig);
document.getElementById("x_coordinate").innerText = x_relative;
document.getElementById("y_coordinate").innerText = y_relative;
document.getElementById("speed").innerText = speed;
document.getElementById("angle").innerText = angle_in_degrees;
//send( x_relative,y_relative,speed,angle_in_degrees);
//send(angle_in_degrees, speed, x_relative, y_relative);
}
}
body {
margin: 0;
padding: 0;
}
.wrapper {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
.top-buttons,
.bot-buttons {
width: 100%;
display: flex;
flex-direction: row;
}
.bot-buttons {
height: 100%;
}
.top-buttons>.left,
.top-buttons>.right {
width: 100%;
display: flex;
flex-direction: row;
}
.bot-buttons>.left {
width: 100%;
display: flex;
margin: auto 0 auto 0;
}
.bot-buttons>.right {
width: auto;
margin: auto 50px auto auto;
display: flex;
flex-direction: row;
}
.bot-buttons>.right>.xyab {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.bot-buttons>.right>.xyab>.xb,
.bot-buttons>.right>.xyab>.a,
.bot-buttons>.right>.xyab>.y {
display: flex;
width: 100%;
}
.bot-buttons>.right>.xyab>.xb {
flex-direction: row;
}
.bot-buttons>.right>.xyab>.xb>.x,
.bot-buttons>.right>.xyab>.xb>.b {
display: flex;
width: 100%;
}
#lt {
width: 70px;
height: 70px;
background: url(assets/360_LT.png) no-repeat;
background-size: 70px 70px;
}
#lb {
width: 70px;
height: 70px;
background: url(assets/360_LB.png) no-repeat;
background-size: 70px 70px;
margin-left: 100px;
}
#rt {
width: 70px;
height: 70px;
background: url(assets/360_RT.png) no-repeat;
background-size: 70px 70px;
margin-left: 100px;
}
#rb {
width: 70px;
height: 70px;
background: url(assets/360_RB.png) no-repeat;
background-size: 70px 70px;
margin-left: auto;
}
#x {
width: 50px;
height: 50px;
background: url(assets/360_X.png) no-repeat;
background-size: 50px 50px;
margin: auto 20px auto auto;
}
#y {
width: 50px;
height: 50px;
background: url(assets/360_Y.png) no-repeat;
background-size: 50px 50px;
margin: auto;
}
#a {
width: 50px;
height: 50px;
background: url(assets/360_A.png) no-repeat;
background-size: 50px 50px;
margin: auto;
}
#b {
width: 50px;
height: 50px;
background: url(assets/360_B.png) no-repeat;
background-size: 50px 50px;
margin: auto auto auto 20px;
}
button,
input[type="submit"],
input[type="reset"] {
background: none;
color: inherit;
border: none;
padding: 0;
font: inherit;
cursor: pointer;
outline: inherit;
}
<html>
<head>
<title>XBOX 360 Virtual</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
</head>
<body scroll="no" style="overflow: hidden;position: fixed;">
<div class="wrapper">
<div class="top-buttons">
<div class="left">
<button id="lt"></button>
<button id="lb"></button>
</div>
<div class="right">
<button id="rb"></button>
<button id="rt"></button>
</div>
</div>
<div class="bot-buttons">
<div class="left">
<div class="lsb">
<p style="text-align: center;">
X: <span id="x_coordinate"> </span> Y: <span id="y_coordinate"> </span> Speed: <span id="speed"> </span> % Angle: <span id="angle"> </span>
</p>
<canvas id="canvas" name="game"></canvas>
</div>
</div>
<div class="right">
<div class="xyab">
<div class="y">
<button id="y"></button>
</div>
<div class="xb">
<div class="x">
<button id="x"></button>
</div>
<div class="b">
<button id="b"></button>
</div>
</div>
<div class="a">
<button id="a"></button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Here is the image:

How can I put Javascript element into CSS background-image

Hi my first javascript project. I wanted to create image in javascript and put it as background for the clock created in css. Everything works great but I don't know how to refer to css .clock so I could put drawn image as background to my css clock (4th line in css file).
I saw other questions but they mostly refer to other javascript drawn images. I want to either add myPiechart.draw as background for css clock or save it as image and set is as background for css clock. Whichever is easier to do. Here you have code below if you copy paste you will see working clock and created image:
html file:
<!DOCTYPE html>
<head>
<link href="styles.css" rel="stylesheet">
<script defer src="script.js"></script>
</head>
<body>
<div class="clock">
<div class="hand hour" data-hour-hand></div>
<div class="hand minute" data-minute-hand></div>
<div class="hand second" data-second-hand></div>
</div>
<canvas id="myCanvas"></canvas>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
javascript file (creating image that I want to be added as background):
var myCanvas = document.getElementById("myCanvas");
myCanvas.width = 300;
myCanvas.height = 300;
var ctx = myCanvas.getContext("2d");
// FUNCTIONS FOR DRAWING CHART
function drawLine(ctx, startX, startY, endX, endY) {
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
}
function drawArc(ctx, centerX, centerY, radius, startAngle, endAngle) {
ctx.beginPath();
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.stroke();
}
function drawPieSlice(ctx, centerX, centerY, radius, startAngle, endAngle, color) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, startAngle - 1.575, endAngle - 1.575);
ctx.closePath();
ctx.fill();
}
// FUNCTION THAT DRAWS PIE CHART
var Piechart = function (options) {
this.options = options;
this.canvas = options.canvas;
this.ctx = this.canvas.getContext("2d");
this.colors = options.colors;
this.draw = function () {
var total_value = 0;
var color_index = 0;
for (var categ in this.options.data) {
var val = this.options.data[categ];
total_value += val;
}
var start_angle = 0;
for (categ in this.options.data) {
val = this.options.data[categ];
var slice_angle = (2 * Math.PI * val) / total_value;
drawPieSlice(
this.ctx,
this.canvas.width / 2,
this.canvas.height / 2,
Math.min(this.canvas.width / 2, this.canvas.height / 2),
start_angle,
start_angle + slice_angle,
this.colors[color_index % this.colors.length]
);
start_angle += slice_angle;
color_index++;
}
};
};
// DATA
var myData = {
"A": 15,
"B": 25,
"C": 12,
"D": 8,
};
// CREATING NEW PIECHART
var myPiechart = new Piechart({
canvas: myCanvas,
data: myData,
// red orange yellow green ADD more colors if needed
colors: ["#FF0000", "#FFBC00", "#FFFF00", "#00FF00"],
});
myPiechart.draw();
// CLOCK PART
setInterval(setClock, 1000);
const hourHand = document.querySelector("[data-hour-hand]");
const minuteHand = document.querySelector("[data-minute-hand]");
const secondHand = document.querySelector("[data-second-hand]");
function setClock() {
const currentDate = new Date();
const secondsRatio = currentDate.getSeconds() / 60;
const minutesRatio = (secondsRatio + currentDate.getMinutes()) / 60;
const hoursRatio = (minutesRatio + currentDate.getHours()) / 12;
setRotation(secondHand, secondsRatio);
setRotation(minuteHand, minutesRatio);
setRotation(hourHand, hoursRatio);
}
function setRotation(element, rotationRatio) {
element.style.setProperty("--rotation", rotationRatio * 360);
}
setClock();
css file (clock):
.clock {
width: 300px;
height: 300px;
/*background-image: url("piechart.png"); *//*HERE I WANT TO ADD PIECHART IMAGE*/
border-radius: 50%;
border: 2px solid black;
position: relative;
}
.clock .number {
--rotation: 0;
position: absolute;
width: 100%;
height: 100%;
text-align: center;
transform: rotate(var(--rotation));
font-size: 1.5rem;
}
.clock .hand {
--rotation: 0;
position: absolute;
bottom: 50%;
left: 50%;
border: 1px solid white;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
transform-origin: bottom;
z-index: 10;
transform: translateX(-50%) rotate(calc(var(--rotation) * 1deg));
}
.clock::after {
content: "";
position: absolute;
background-color: black;
z-index: 11;
width: 15px;
height: 15px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
}
.clock .hand.second {
width: 3px;
height: 45%;
background-color: red;
}
.clock .hand.minute {
width: 7px;
height: 40%;
background-color: black;
}
.clock .hand.hour {
width: 10px;
height: 35%;
background-color: black;
}
If there are better ways to do this I'm open to suggestions.
Place element canvas#myCanvas as a child of div.clock
<div class="clock">
<div class="hand hour" data-hour-hand></div>
<div class="hand minute" data-minute-hand></div>
<div class="hand second" data-second-hand></div>
<canvas id="myCanvas"></canvas>
</div>

How to draw a rectangle manually in html without canvas?

What I mean is understood better in this photo
In the given photo, I used canvas for drawings; however, I would like to do it by an another way because I want to created rectangles be draggable and give ids to created rectangles. For example, If I used div instead of canvas, I could not manually draw the rectangles like in the photo. Maybe, there is a way but I don't know it. When I searched this subject, most of the people use paper.js, etc. but it is just useful in resize or drag&drop; therefore, I did not want to use these.
function lettersOnly(input) {
var regex = /[^a-z]/gi;
input.value = input.value.replace(regex, "");
}
jQuery(document).ready(function($) {
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var canvasOffset = $("#canvas").offset();
var canvasx = canvasOffset.left;
var canvasy = canvasOffset.top;
var last_mousex = 0;
var last_mousey = 0;
var mousex = 0;
var mousey = 0;
var mousedown = false;
var shapes = [];
var width;
var height;
// make var col a global variable
var col = "black";
var ad = "";
//Mousedown
$(canvas).on('mousedown', function(e) {
last_mousex = parseInt(e.clientX - canvasx);
last_mousey = parseInt(e.clientY - canvasy);
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
const lastPos = {
lastMouseX: last_mousex,
lastMouseY: last_mousey,
rectWidth: width,
rectHeight: height,
// save the color of the rect
color: col,
name: ad
};
shapes.push(lastPos);
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
mousex = parseInt(e.clientX - canvasx);
mousey = parseInt(e.clientY - canvasy);
if (mousedown) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
width = mousex - last_mousex;
height = mousey - last_mousey;
col = $("#color").val();
ad = $("#name").val();
if (shapes.length > 0) {
for (var i in shapes) {
// for every shape in the shapes array beginPath
ctx.beginPath();
//set the color of the stroke
ctx.strokeStyle = shapes[i].color;
//draw the rect
ctx.rect(shapes[i].lastMouseX, shapes[i].lastMouseY, shapes[i].rectWidth, shapes[i].rectHeight);
ctx.fillText(shapes[i].name, shapes[i].rectWidth - shapes[i].lastMouseX, shapes[i].rectHeight - shapes[i].lastMouseY);
ctx.stroke();
}
}
//for the new rect beginPath
ctx.beginPath();
ctx.rect(last_mousex, last_mousey, width, height);
ctx.strokeStyle = col;
ctx.lineWidth = 3;
ctx.fillText(ad, 100, 100);
ctx.stroke();
}
$('#output').html('Current Coordinate: ' + mousex + ', ' + mousey + '<br/>Last Coordinate: ' + last_mousex + ', ' + last_mousey);
});
});
.topnav {
background-color: #333;
overflow: hidden;
}
/* Style the links inside the navigation bar */
.topnav a {
float: left;
color: #f2f2f2;
text-align: center;
padding: 14px 16px;
text-decoration: none;
font-size: 14px;
}
/* Change the color of links on hover */
.topnav a:hover {
background-color: #ddd;
color: black;
}
/* Add a color to the active/current link */
.topnav a.active {
background-color: #4CAF50;
color: white;
}
#color {
border: 1px solid black;
font-family: 'Times New Roman', Times, serif;
font-size: 14px;
margin: auto;
padding: 0;
position: absolute;
top: 0;
left: 45%;
right: 0;
text-align: center;
}
#name {
border: 1px solid black;
font-family: 'Times New Roman', Times, serif;
font-size: 14px;
margin: auto;
padding: 0;
position: absolute;
top: 0;
left: 45%;
right: 0;
text-align: center;
}
.submit {
border: 1px solid black;
margin: auto;
padding: 0;
width: 70px;
height: 30px;
position: absolute;
top: 0;
left: 0;
right: 0;
font-family: 'Times New Roman', Times, serif;
font-size: 14px;
text-align: center;
}
#canvas {
cursor: crosshair;
background-image: url("kroki2v3.png");
background-repeat: no-repeat;
background-size: contain;
padding: 0;
margin-left: 210;
margin-top: 160;
position: static;
display: block;
}
#output {
font-family: 'Times New Roman', Times, serif;
font-size: 14px;
top: 19%;
left: 46%;
position: absolute;
}
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<div>
<table>
<tr>
<td><input type="text" id="color" style="margin-top: 70px" placeholder="Color" onkeyup="lettersOnly(this)" /></td>
<td><input type="text" id="name" style="margin-top: 100px;" placeholder="Department Name" onkeyup="lettersOnly(this)" /></td>
<td><input type="submit" class="submit" value="Submit" style="margin-top: 130px;" /></td>
</tr>
</table>
</div>
<div class="topnav">
<a class="active" href="">Project</a>
Contact
About
</div>
<div id="container" style="display: none;"><img src="kroki2v3.png" id="img01" alt="" style="display: none;"></div>
<canvas id="canvas" width="1200" height="520"></canvas>
<div id="output"></div>
</body>
</html>
Something like this? When you say "draw", this is what I imagined.
You need to find the mouse position in the mousedown function and in the mousemove function, then subtract the mousedown x and y position from the mousemove x and y position to set the width and height.
You also need to set a variable to tell whether or not the mouse is actually down while moving the mouse to ensure a div isn't "drawn" without knowledge.
Once you "mouseup" you can set your draggable / resizable functions to be used.
Here is a fiddle;
$(function() {
var widget;
var x;
var y;
var finX;
var finY;
var ismousedown = false;
$(document).on({
mousedown: function(event) {
if ($(event.target).attr('class') == 'wrapper') {
x = event.pageX;
y = event.pageY;
$('body').append('<div class="widget" style="top:' + y + 'px; left: ' + x + 'px;"></div>');
widget = $('.widget').last();
ismousedown = true;
}
},
mousemove: function(event) {
if (ismousedown == true) {
finX = event.pageX;
finY = event.pageY;
widget.width(finX - x);
widget.height(finY - y);
widget.css({
'width': (finX - x) + '!important',
'height': (finY - y) + '!important',
'display': 'block',
'border': '2px dashed #ccc'
});
}
},
mouseup: function(event) {
ismousedown = false;
widget.css({
'background': '#222',
'border': '0',
'cursor': 'move'
});
initDraggable();
}
});
// in case you need to reinitialize later.
function initDraggable() {
$('.widget').draggable({});
}
});
html,
body {
height: 100% !important;
position: relative;
}
.wrapper {
position: relative;
height: 100% !important;
width: 100% !important;
}
.widget {
display: block;
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="wrapper">
</div>

3 Divs side by side overflow one another

I've been chasing around this problem for hours, here's the code:
<!DOCTYPE html>
<html>
<head>
<style>
html, body{
height: 100%;
max-height: 100%;
overflow:hidden;
}
.controls{
display: table;
height: 10%;
margin-top: 1%;
width: 100%;
}
#w1 {
width:25%;
}
#can
float: left;
padding: 0;
margin: 0;
top: 0;
}
#canTwo{
float: left;
padding: 0;
margin: 0;
top: 0;
}
textarea {
outline: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
font-size: 1.25vw;
height: 100%;
width: 100%;
}
#w2{
width:50%;
}
#w3{
width:25%;
}
.controlbuttons {
display: table-cell;
height: 100%;
}
</style>
</head>
<body>
<div class="controls">
<div class="controlbuttons" id="w1"><canvas id = "can" width = "0" height = "0"></div>
<div class="controlbuttons" id="w2"><textarea rows="3" cols="50"></textarea></div>
<div class="controlbuttons" id="w3"><canvas id = "canTwo" width = "0" height = "0"></div>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
fitToContainer();
});
var canvas = document.getElementById("can"),
ctx = canvas.getContext('2d'),
canvasTwo = document.getElementById("canTwo"),
ctxTwo = canvasTwo.getContext('2d');
function fitToContainer(){
var control = document.getElementsByClassName("controlbuttons")[0];
var h = control.clientHeight;
var w = control.clientWidth;
canvas.height = h;
canvas.width = w;
canvasTwo.height = h;
canvasTwo.width = w;
ctx.fillStyle = "green";
ctx.fillRect(0, 0, 5000, 5000);
ctxTwo.fillStyle = "green";
ctxTwo.fillRect(0, 0, 5000, 5000);
}
</script>
</body>
</html>
jsfiddle:
https://jsfiddle.net/ca3uw837/
Basically I have one textarea and it's width takes 50% of the page and it is exactly in the middle, there are two
canvases to it's side which take 25% width.
I am trying to get them to align perfectly(same height, exactly one next to the other) but here is how it looks on my pc:
What am I supposed to do? use flexbox? I am not sure I know how to achieve it as canvases are very tricky with their sizing technique. Thank you so much for your time.
Apply flexbox to .controls to align the child elements. Also apply box-sizing: border-box to textbox as the default padding adds with the 100% height of the textbox. border-box will make the padding inclusive of height.
document.addEventListener("DOMContentLoaded", function(event) {
fitToContainer();
});
var canvas = document.getElementById("can"),
ctx = canvas.getContext('2d'),
canvasTwo = document.getElementById("canTwo"),
ctxTwo = canvasTwo.getContext('2d');
function fitToContainer() {
var control = document.getElementsByClassName("controlbuttons")[0];
var h = control.clientHeight;
var w = control.clientWidth;
canvas.height = h;
canvas.width = w;
canvasTwo.height = h;
canvasTwo.width = w;
ctx.fillStyle = "green";
ctx.fillRect(0, 0, 5000, 5000);
ctxTwo.fillStyle = "green";
ctxTwo.fillRect(0, 0, 5000, 5000);
}
html,
body {
height: 100%;
max-height: 100%;
overflow: hidden;
}
.controls {
display: flex;
height: 10%;
margin-top: 1%;
width: 100%;
}
#w1 {
width: 25%;
}
#can float: left;
padding: 0;
margin: 0;
top: 0;
}
#canTwo {
float: left;
padding: 0;
margin: 0;
top: 0;
}
textarea {
outline: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
font-size: 1.25vw;
height: 100%;
width: 100%;
box-sizing: border-box;
}
#w2 {
width: 50%;
}
#w3 {
width: 25%;
}
.controlbuttons {
height: 100%;
}
<div class="controls">
<div class="controlbuttons" id="w1"><canvas id="can" width="0" height="0"></div>
<div class="controlbuttons" id="w2"><textarea rows="3" cols="50"></textarea></div>
<div class="controlbuttons" id="w3"><canvas id = "canTwo" width = "0" height = "0"></div>
</div>
To align table-cell items to the top you should use: vertical-align: top. Both canvas are missing height and width property, set them to 100%. Add box-sizing: border-box to the textarea:
box-sizing: border-box
The width and height properties (and min/max properties) includes
content, padding and border, but not the margin
So:
textarea {
/** ... rest of styles ...*/
margin: 0;
box-sizing: border-box;
float: left;
}
.controlbuttons { vertical-align: top; } /* Align items to the top */
.controlbuttons canvas { height: 100%; width: 100%; }
Demo: (Tested in firefox 53.0.2 & Chrome 56.0.2924.87)
document.addEventListener("DOMContentLoaded", function(event) {
fitToContainer();
});
var canvas = document.getElementById("can"),
ctx = canvas.getContext('2d'),
canvasTwo = document.getElementById("canTwo"),
ctxTwo = canvasTwo.getContext('2d');
function fitToContainer() {
var control = document.getElementsByClassName("controlbuttons")[0];
var h = control.clientHeight;
var w = control.clientWidth;
canvas.height = h;
canvas.width = w;
canvasTwo.height = h;
canvasTwo.width = w;
ctx.fillStyle = "green";
ctx.fillRect(0, 0, 5000, 5000);
ctxTwo.fillStyle = "green";
ctxTwo.fillRect(0, 0, 5000, 5000);
}
html,
body {
height: 100%;
max-height: 100%;
overflow: hidden;
}
.controls {
display: table;
height: 10%;
margin-top: 1%;
width: 100%;
}
#w1 {
width: 25%;
}
textarea {
outline: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
font-size: 1.25vw;
height: 100%;
width: 100%;
margin: 0;
box-sizing: border-box;
float: left;
}
#w2 {
width: 50%;
}
#w3 {
width: 25%;
}
.controlbuttons {
display: table-cell;
height: 100%;
vertical-align: top;
}
.controlbuttons canvas {
float: left;
padding: 0;
margin: 0;
top: 0;
height: 100%;
width: 100%;
}
<!DOCTYPE html>
<html>
<body>
<div class="controls">
<div class="controlbuttons" id="w1">
<canvas id="can" width="0" height="0"></canvas>
</div>
<div class="controlbuttons" id="w2">
<textarea rows="3" cols="50"></textarea>
</div>
<div class="controlbuttons" id="w3">
<canvas id = "canTwo" width = "0" height = "0"></canvas>
</div>
</div>
</body>
</html>

Categories

Resources