How to make image fit on canvas without deforming - javascript

How to fit img to canvas, each time I put the //commented code the canvas disapears, I don't know how to get around this one. So i gave it a few tries but the frame goes away and I would like the canvas to take the size of the image so no stretching or deforming. There must be a simple line to add just for the format. Currently the image goes beyonf the canvas format from the left top up.
window.requestAnimFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1e3 / 60)
}
let curCanvas = document.getElementById('canvas0')
let curCtx = curCanvas.getContext('2d')
let imgCanvas = document.getElementById('canvas-ref')
let imgCtx = imgCanvas.getContext('2d')
curCanvas.width = parent.innerWidth
curCanvas.height = parent.innerHeight
// imgCanvas.width = window.innerWidth
// imgCanvas.height = window.innerHeight
// Create a variable for the canvas and it's context
// var canvas = document.getElementById("canvas-ref");
// var ctx = canvas.getContext("2d");
// // Initialise an image object
// var image = new Image();
// // When it loads an image
// image.onload = function() {
// // Get the canvas' current style
// var canvasStyle = getComputedStyle(canvas);
// // Get it's current width, minus the px at the end
// var canvasWidth = canvasStyle.width.replace("px", "");
// // Work out the images ratio
// var imageRatio = this.width/this.height;
// // Work out the new height of the canvas, keeping in ratio with the image
// var canvasHeight = canvasWidth/imageRatio;
// // Set the canvas' height in the style tag to be correct
// canvas.style.height = canvasHeight+"px";
// // Set the width/height attributes to be correct (as this is what drawImage uses)
// canvas.width = canvasWidth;
// canvas.height = canvasHeight;
// // Draw the image at the right width/height
// ctx.drawImage(this, 0, 0, canvasWidth, canvasHeight);
// };
// Reference image
const img = new Image();
img.onload = () => {
imgCanvas.width = img.naturalWidth
imgCanvas.height = img.naturalHeight
imgCtx.clearRect(0, 0, imgCanvas.width, imgCanvas.height);
imgCtx.drawImage(img, 0, 0);
}
// const img = new Image();
// image.src = "imgURL";
// image.onload = function(){
// scaleToFit(this);
// }
// function scaleToFit(img){
// // get the scale
// var scale = Math.min(canvas.width / img.width, canvas.height / img.height);
// // get the top left position of the image
// var x = (canvas.width / 2) - (img.width / 2) * scale;
// var y = (canvas.height / 2) - (img.height / 2) * scale;
// ctx.drawImage(img, x, y, img.width * scale, img.height * scale);
// }
// img.onload = () => {
// imgCanvas.width = img.naturalWidth
// imgCanvas.height = img.naturalHeight
// imgCtx.clearRect(0, 0, imgCanvas.width, imgCanvas.height);
// imgCtx.drawImage(img, 0, 0);
// }
curCtx.strokeStyle = '#555'
let mouse = {
cut: 8,
influence: 50,
down: false,
button: 1,
x: 0,
y: 0,
px: 0,
py: 0
}
class Point {
constructor(x, y) {
this.x = x
this.y = y
this.px = x
this.py = y
this.vx = 0
this.vy = 0
this.pinX = null
this.pinY = null
this.origx = x;
this.origy = y;
canvas1
this.constraints = []
}
update(delta) {
if (this.pinX && this.pinY) return this
if (mouse.down) {
let dx = this.x - mouse.x
let dy = this.y - mouse.y
let dist = Math.sqrt(dx * dx + dy * dy)
if (mouse.button === 1 && dist < mouse.influence) {
this.px = this.x - (mouse.x - mouse.px)
this.py = this.y - (mouse.y - mouse.py)
} else if (dist < mouse.cut) {
this.constraints = []
}
}
this.addForce(0, gravity)
let nx = this.x + (this.x - this.px) * friction + this.vx * delta
let ny = this.y + (this.y - this.py) * friction + this.vy * delta
this.px = this.x
this.py = this.y
this.x = nx
this.y = ny
this.vy = this.vx = 0
if (this.x >= curCanvas.width) {
this.px = curCanvas.width + (curCanvas.width - this.px) * bounce
this.x = curCanvas.width
} else if (this.x <= 0) {
this.px *= -1 * bounce
this.x = 0
}
if (this.y >= curCanvas.height) {
this.py = curCanvas.height + (curCanvas.height - this.py) * bounce
this.y = curCanvas.height
} else if (this.y <= 0) {
this.py *= -1 * bounce
this.y = 0
}
return this
}
draw() {
let i = this.constraints.length
while (i--) this.constraints[i].draw()
}
resolve() {
if (this.pinX && this.pinY) {
this.x = this.pinX
this.y = this.pinY
return
}
this.constraints.forEach((constraint) => constraint.resolve())
}
attach(point) {
this.constraints.push(new Constraint(this, point))
}
free(constraint) {
this.constraints.splice(this.constraints.indexOf(constraint), 1)
}
addForce(x, y) {
this.vx += x
this.vy += y
}
pin(pinx, piny) {
this.pinX = pinx
this.pinY = piny
}
}
class Constraint {
constructor(p1, p2) {
this.p1 = p1
this.p2 = p2
this.length = spacing
}
resolve() {
let dx = this.p1.x - this.p2.x
let dy = this.p1.y - this.p2.y
let dist = Math.sqrt(dx * dx + dy * dy)
if (dist < this.length) return
let diff = (this.length - dist) / dist
if (dist > tearDist) this.p1.free(this)
let mul = diff * 0.5 * (1 - this.length / dist)
let px = dx * mul
let py = dy * mul
!this.p1.pinX && (this.p1.x += px)
!this.p1.pinY && (this.p1.y += py)
!this.p2.pinX && (this.p2.x -= px)
!this.p2.pinY && (this.p2.y -= py)
return this
}
draw() {
curCtx.drawImage(imgCanvas, this.p1.origx, this.p1.origy,
spacing, spacing, this.p1.x, this.p1.y, spacing + 1, spacing + 1);
}
}
class Cloth {
constructor() {
this.points = []
let startX = curCanvas.width / 2 - (clothWidth * spacing / 2)
console.log("Start x", startX);
for (let y = 0; y <= clothHeight; y++) {
for (let x = 0; x <= clothWidth; x++) {
let point = new Point(startX + x * spacing, 5 + y * spacing)
y === 0 && point.pin(point.x, point.y)
x !== 0 && point.attach(this.points[this.points.length - 1])
y !== 0 && point.attach(this.points[x + (y - 1) * (clothWidth + 1)])
this.points.push(point)
}
}
}
update(delta) {
let i = accuracy
while (i--) {
this.points.forEach((point) => {
point.resolve()
})
}
curCtx.beginPath()
this.points.forEach((point) => {
point.update(delta * delta).draw()
})
curCtx.stroke()
}
}
function setMouse(e) {
if (curCanvas === null) return;
let rect = curCanvas.getBoundingClientRect()
mouse.px = mouse.x
mouse.py = mouse.y
mouse.x = e.clientX - rect.left * 0.5
mouse.y = e.clientY - rect.top
}
function bindEvents(c) {
if (curCanvas === null) return;
c.onmousedown = (e) => {
mouse.button = e.which
mouse.down = true
setMouse(e)
}
c.onmousemove = setMouse
c.onmouseup = () => (mouse.down = false)
c.oncontextmenu = (e) => e.preventDefault()
}
function load_canvas(id) {
console.log("Loading canvas ", id);
switch (id) {
case 0:
canvas0();
break;
case 1:
canvas1();
break;
case 2:
canvas2();
break;
case 3:
canvas3();
break;
case 4:
canvas4();
break;
case 5:
canvas5();
break;
case 6:
canvas6();
break;
case 7:
canvas7();
break;
case 8:
canvas8();
break;
case 9:
canvas9();
break;
case 10:
canvas10();
break;
case 11:
canvas11();
break;
default:
break;
}
console.log("Binding mouse events");
bindEvents(curCanvas)
}
window.onload = function () {
load_canvas(0) // Ne pas modifier
}

I don't know exactly if I understood your question right.
Because every image has a different aspect ratio, I'd suggest to fit the canvas to the size of the image.
Here, I hide the image and set width and height of the canvas accordingly and render the image into the canvas.
Maybe this helps.
I do this on every change of windows size.
You can set the image width and height via css.
window.onload = drawFullImage;
window.onresize = drawFullImage;
function drawFullImage() {
var c = document.getElementById("myCanvas");
var imageDiv = document.getElementById("imagetorender");
c.width = imageDiv.getBoundingClientRect().width;
c.height = imageDiv.getBoundingClientRect().height;
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
var img = document.getElementById("imagetorender");
ctx.drawImage(img, 0, 0, c.width, c.height);
}
body {
position: relative;
margin: 0;
}
#imagetorender {
visibility: hidden;
overflow: auto;
width: 400px;
}
#myCanvas {
position: absolute;
top: 0;
left: 0;
}
<div id="wrapper">
<img id="imagetorender" src="http://farm5.static.flickr.com/4005/4706825697_c0367e6dee_b.jpg" />
<canvas id="myCanvas"></canvas>
</div>

Related

How to remove black background from this JS coding?

I'm trying to make this particle text be on a transparent background to add onto a slideshow. Can someone assist? I cannot seem to find where it is stated within the code.
Here is the JS code. Sorry I can't seem to get it to fit properly within the code section of the post.
class Particles { constructor(x, y, texture, size) {
this.x = x;
this.y = y;
this.sprite = new PIXI.Sprite(new PIXI.Texture.from(texture));
this.sprite.texture.frame = new PIXI.Rectangle(x, y, size, size);
this.sprite.x = x;
this.sprite.y = y;
this.speedX = 0;
this.speedY = 0;
this.radius = 100;
this.gravity = 0.1;
this.maxGravity = 0.01 + Math.random() * 0.03;
this.friction = 0.9;
this.dirX = Math.random() - 0.5;
this.dirY = Math.random() - 0.5; }
update(mouse) {
const distanceX = mouse.x - this.sprite.x;
const distanceY = mouse.y - this.sprite.y;
const distanceSqrd = distanceX * distanceX + distanceY * distanceY;
if (distanceSqrd < this.radius * this.radius && distanceSqrd > 0) {
const distance = Math.sqrt(distanceSqrd);
let normalX = distanceX / distance;
let normalY = distanceY / distance;
this.speedX -= normalX;
this.speedY -= normalY;
this.gravity *= this.friction;
} else {
this.gravity += 0.1 * (this.maxGravity - this.gravity);
}
let oDistX = this.x - this.sprite.x;
let oDistY = this.y - this.sprite.y;
this.speedX += oDistX * this.gravity;
this.speedY += oDistY * this.gravity;
this.speedX *= this.friction;
this.speedY *= this.friction;
this.sprite.x += this.speedX;
this.sprite.y += this.speedY; } }
class ParticlesText { constructor({ text, size }) {
this.app = new PIXI.Application({ width: innerWidth, height: innerHeight });
document.querySelector("#content-canvas").append(this.app.view);
this.text = text;
this.size = size;
this.cols = 500;
this.rows = 200;
this.pSize = 2;
this.particles = [];
this.mouse = {x: 0, y: 0}
this.container = new PIXI.particles.ParticleContainer(50000);
this.app.stage.addChild(this.container);
this.onResize = this.onResize.bind(this); }
init() {
const that = this;
opentype.load(
"https://raw.githack.com/AlainBarrios/Fonts/master/LeagueSpartan-Bold.otf",
function(err, font) {
if (err) {
alert("Font could not be loaded: " + err);
} else {
const canvas = document.createElement("canvas");
// Now let's display it on a canvas with id "canvas"
const ctx = canvas.getContext("2d");
// Construct a Path object containing the letter shapes of the given text.
// The other parameters are x, y and fontSize.
// Note that y is the position of the baseline.
const path = font.getPath(that.text, 0, that.size, that.size);
const width = font.getAdvanceWidth(that.text, that.size);
that.cols = width;
that.rows = that.size;
canvas.width = width;
canvas.height = that.size;
path.fill = "rgba(255,255,255,1)";
// If you just want to draw the text you can also use font.draw(ctx, text, x, y, fontSize).
path.draw(ctx);
that.addObjects(canvas, ctx);
}
}
); }
isEmpty(x, y, ctx) {
const image = ctx.getImageData(x, y, this.pSize, this.pSize);
let emptyCounter = 0;
for (let i = 0; (length = image.data.length), i < length; i += 4) {
if (image.data[i + 3] !== 0) {
continue;
}
emptyCounter++;
}
return emptyCounter === this.pSize * this.pSize; }
addObjects(canvas, ctx) {
this.container.x = this.app.renderer.width / 2 - this.cols / 2;
this.container.y = this.app.renderer.height / 2 - this.rows / 2;
for (let i = 0; i < this.cols; i += 1) {
for (let j = 0; j < this.rows; j += 1) {
const x = i * this.pSize;
const y = j * this.pSize;
if (this.isEmpty(x, y, ctx)) continue;
const p = new Particles(x, y, canvas, this.pSize);
this.particles.push(p);
this.container.addChild(p.sprite);
}
}
this.container.interactive = true;
this.onResize();
window.addEventListener("resize", this.onResize);
this.container.on("mousemove", e => {
this.mouse = e.data.getLocalPosition(this.container);
});
this.animate(); }
onResize() {
const { innerWidth, innerHeight } = window;
const size = [innerWidth, innerHeight];
const ratio = size[0] / size[1];
if (innerWidth / innerHeight >= ratio) {
var w = innerHeight * ratio;
var h = innerHeight;
} else {
var w = innerWidth;
var h = innerWidth / ratio;
}
//this.app.renderer.view.style.width = w + "px";
//this.app.renderer.view.style.height = h + "px"; }
animate() {
this.app.ticker.add(() => {
stats.begin();
this.particles.forEach(p => {
p.update(this.mouse);
});
stats.end();
}); } }
const particles = new ParticlesText({ text: "KILL THE ROBOTS", size:
150 }); particles.init();

Why won't the image load

What is wrong with the code, I can't find the problem. I think it's because of the drawFrame and loadImage function, but I don't know. So is there a way to make the image load and you will still be able to move it around and shoot?
And when I try to remove the drawFrame function nothing would work. And if posiible is there a way to change the bullet from squares to circles?
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="UTF-8">
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
canvas {
cursor: crosshair;
background-color: cornflowerblue;
}
</style>
</head>
<body>
<canvas id="Trump"></canvas>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
(async function main() {
var canvas = document.getElementById('Trump');
if (!canvas.getContext) return;
var ctx = canvas.getContext('2d');
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
//const fps = 60;
const ronaNum = 30; // number of particles at start
const ronaSize = 70; // corona size
const ronaSpeed = 100; // speed
let chinabmg;
function draw() {
$("canvas").one("click", function () {
chinabmg = new sound("stankytrumpchina.mp3");
chinabmg.play();
});
//mutes when clicked on m
document.body.onkeyup = function (e) {
if (e.keyCode == 77) { chinabmg.stop() }
};
//compatability
var requestAnimationFrame = window.requestAnimationFrame || //Chromium
window.webkitRequestAnimationFrame || //Webkit
window.mozRequestAnimationFrame || //Mozilla Geko
window.oRequestAnimationFrame || //Opera Presto
window.msRequestAnimationFrame || //IE Trident?
function (callback) { //Fallback function
window.setTimeout(callback, 1000 / 60);
};
var DrawX = 0;
var DrawY = 0;
var time = 0;
var width = canvas.width;
var height = canvas.height;
var offTop = canvas.offsetTop;
var offLeft = canvas.offsetLeft;
var rectWidth = 15;
var rectHeight = 15;
var speed = 1;
var x = width / 2;
var y = height / 2;
var size = 30;
var id = 0;
var bulletId = 0;
function sound(src) {
this.sound = document.createElement("audio");
this.sound.src = src;
this.sound.setAttribute("preload", "auto");
this.sound.setAttribute("controls", "none");
this.sound.setAttribute("loop", "auto");
this.sound.style.display = "none";
document.body.appendChild(this.sound);
this.play = function () {
this.sound.play();
}
this.stop = function () {
this.sound.pause();
}
}
function player(id, color, size, x, y) {
this.id = id;
this.color = color;
this.size = size;
this.x = x;
this.y = y;
this.speed = speed;
}
var playerList = [];
function addPlayer(color, size, x, y) {
playerList[id] = new player(id, color, size, x, y);
id += 1;
}
addPlayer("blue", size, width / 2 - 50, height / 2);
var pressedKeys = [];
function moveLeft(checkId, checkX, checkY, cSize, cSpeed, cKey) {
var x = checkX - cSpeed;
var y = checkY - cSpeed;
var x2 = checkX + cSize + cSpeed;
var y2 = checkY + cSize + cSpeed;
if (x > 0) {
playerList[checkId].x = checkX - cSpeed;
} else {
playerList[checkId].x = 0;
}
}
function moveUp(checkId, checkX, checkY, cSize, cSpeed, cKey) {
var x = checkX - cSpeed;
var y = checkY - cSpeed;
var x2 = checkX + cSize + cSpeed;
var y2 = checkY + cSize + cSpeed;
if (y > 0) {
playerList[checkId].y = checkY - cSpeed;
} else {
playerList[checkId].y = 0;
}
}
function moveRight(checkId, checkX, checkY, cSize, cSpeed, cKey) {
var x = checkX - cSpeed;
var y = checkY - cSpeed;
var x2 = checkX + cSize + cSpeed;
var y2 = checkY + cSize + cSpeed;
if (x2 < width) {
playerList[checkId].x = checkX + cSpeed;
} else {
playerList[checkId].x = width - cSize;
}
}
function moveDown(checkId, checkX, checkY, cSize, cSpeed, cKey) {
var x = checkX - cSpeed;
var y = checkY - cSpeed;
var x2 = checkX + cSize + cSpeed;
var y2 = checkY + cSize + cSpeed;
if (y2 < height) {
playerList[checkId].y = checkY + cSpeed;
} else {
playerList[checkId].y = height - cSize;
}
}
function Move(checkId, checkX, checkY, cSize, cSpeed, cKey) {
if (checkId === 0) {
switch (cKey) {
case 65:
// left
moveLeft(checkId, checkX, checkY, cSize, cSpeed, cKey);
break;
case 87:
// up
moveUp(checkId, checkX, checkY, cSize, cSpeed, cKey);
break;
case 68:
// right
moveRight(checkId, checkX, checkY, cSize, cSpeed, cKey);
break;
case 83:
// down
moveDown(checkId, checkX, checkY, cSize, cSpeed, cKey);
break;
default:
return; // exit this handler for other keys
}
}
}
var validKeys = [];
validKeys[0] = "65,87,68,83-107,109,80";
// == KEYDOWN ==
$(document.body).keydown(function (e) {
e.preventDefault();
//go through all players
$.each(playerList, function (i, currentPlayer) {
if (validKeys[currentPlayer.id].indexOf(e.which) == -1) return true;
if (!pressedKeys[e.which]) {
//set interval for the function
pressedKeys[e.which] = setInterval(function () {
Move(currentPlayer.id, currentPlayer.x, currentPlayer.y, currentPlayer.size, currentPlayer.speed, e.which);
}, 5);
}
});
});
// == KEYUP ==
$(document.body).keyup(function (e) {
if (pressedKeys[e.which]) {
clearInterval(pressedKeys[e.which]);
delete pressedKeys[e.which];
}
});
//=============================== SHOOTING ===============================
//Bullets
function bullet(id, color, size, speed, x, y, eX, eY) {
this.id = id;
this.color = color;
this.size = size;
this.x = x;
this.y = y;
this.eX = eX;
this.eY = eY;
this.velocityX = 1;
this.velocityY = 1;
this.speed = 9;
}
var bulletList = [];
function addBullet(color, bsize, bspeed, x, y, eX, eY) {
bulletList[bulletId] = new bullet(bulletId, color, bsize, 9, x, y, eX, eY);
bulletId += 1;
}
function updateBullet(bullet, player) {
var dx = (bullet.eX - player.x);
var dy = (bullet.eY - player.y);
var mag = Math.sqrt(dx * dx + dy * dy);
bullet.velocityX = (dx / mag) * 9;
bullet.velocityY = (dy / mag) * 9;
bullet.x += bullet.velocityX;
bullet.y += bullet.velocityY;
}
// Add event listener for `click` events.
canvas.onmousedown = function (e) {
addBullet("#696969", 10, 2, playerList[0].x, playerList[0].y, e.x, e.y);
};
//corona part
let corona = [];
createCoronaParticles();
// game loop
//setInterval(update, 1000 / fps);
function createCoronaParticles() {
corona = [];
let cx, cy;
for (var i = 0; i < ronaNum; i++) {
do {
cx = Math.floor(Math.random() * canvas.width);
cy = Math.floor(Math.random() * canvas.height);
} while (noSpawnOnFigure(canvas.height / 2, canvas.width / 2, cy, cx) < ronaSize * 5);
corona.push(newParticle(cx, cy));
}
}
function noSpawnOnFigure(cy1, cx1, cy2, cx2) {
return Math.sqrt(Math.pow(cy2 - cy1, 2) + Math.pow(cx2 - cx1, 2));
}
function newParticle(cx, cy) {
let rona = {
ca: Math.random() * Math.PI * 2, //radians
cr: ronaSize / 2,
cx: cx,
cy: cy,
cxv: Math.random() * ronaSpeed / 60 * (Math.random() < 0.5 ? 1 : -1),
cyv: Math.random() * ronaSpeed / 60 * (Math.random() < 0.5 ? 1 : -1)
};
return rona;
}
// function update() {
// }
// ======= DRAWING =======
function drawFrame() {
requestAnimationFrame(drawFrame);
ctx.font = "15pt Georgia"; // sets the font and font size of the text
ctx.clearRect(0, 0, width, height);
$.each(playerList, function (index, currentPlayer) {
//debug
//draw players
function loadImage(path) {
let image = new Image();
let promise = new Promise((resolve, reject) => {
image.onload = () => resolve(image);
image.onerror = reject
});
image.src = path;
return promise;
}
loadImage.src = 'trump.gif';
});
//draw bullets
$.each(bulletList, function (index, bullet) {
updateBullet(bullet, playerList[0]);
ctx.fillStyle = bullet.color;
ctx.fillRect(bullet.x, bullet.y, bullet.size, bullet.size);
});
// canvas
//ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw corona particles
ctx.strokeStyle = "rgb(150, 0, 0)";
ctx.lineWidth = 20;
let ca, cr, cx, cy;
for (let i = 0; i < corona.length; i++) {
// get properties
ca = corona[i].ca;
cr = corona[i].cr;
cx = corona[i].cx;
cy = corona[i].cy;
// draw path
ctx.beginPath();
ctx.fillStyle = "rgb(200, 0, 0)"
ctx.moveTo(
cx + cr * Math.cos(ca),
cy + cr * Math.sin(ca)
);
// draw circle
for (let j = 1; j < 180; j++) {
ctx.lineTo(
cx + cr * Math.cos(ca + j * Math.PI * 2 / 180),
cy + cr * Math.sin(ca + j * Math.PI * 2 / 180)
);
}
ctx.closePath();
ctx.stroke();
ctx.fill();
// move particles
corona[i].cx += corona[i].cxv;
corona[i].cy += corona[i].cyv;
// particle edge of screen
if (corona[i].cx < 0 - corona[i].cr) {
corona[i].cx = canvas.width + corona[i].cr;
} else if (corona[i].cx > canvas.width + corona[i].cr) {
corona[i].cx = 0 - corona[i].cr
}
if (corona[i].cy < 0 - corona[i].cr) {
corona[i].cy = canvas.height + corona[i].cr;
} else if (corona[i].cy > canvas.height + corona[i].cr) {
corona[i].cy = 0 - corona[i].cr
}
}
}
drawFrame();
}
$(draw);
}
)();
</script>
</body>
</html>
//draw players
function loadImage(path) {
let image = new Image();
let promise = new Promise((resolve, reject) => {
image.onload = () => resolve(image);
image.onerror = reject
});
image.src = path;
//Add the following line
ctx.drawImage(image,playerList[0].x,playerList[0].y);
return promise;
}
// change loadImage.src = 'trump.gif' into this
loadImage('trump.gif');

arrow with modification point

Hi I'm trying to reproduce a draw.io effect. When you draw an arrow it display a blue point in the middle of the arrow that allows you to create angle between the two lines and it display two blue point that allow you to do the same with the two new line. I have added image below. It'll be easier to understand.
I wonder how to code dynamically these blue points that allow to "break" the line
var ctx = tempcanvas.getContext('2d'),
mainctx = canvas.getContext('2d'),
w = canvas.width,
h = canvas.height,
x1,
y1,
isDown = false;
ctx.translate(0.5, 0.5);
tempcanvas.onmousedown = function(e) {
var rect = canvas.getBoundingClientRect();
x1 = e.clientX - rect.left;
y1 = e.clientY - rect.top;
isDown = true;
}
tempcanvas.onmouseup = function() {
isDown = false;
mainctx.drawImage(tempcanvas, 0, 0);
ctx.clearRect(0, 0, w, h);
}
tempcanvas.onmousemove = function(e) {
if (!isDown) return;
var rect = canvas.getBoundingClientRect(),
x2 = e.clientX - rect.left,
y2 = e.clientY - rect.top;
var p0={x1,y1};
var p1={x2,y2};
ctx.clearRect(0, 0, w, h);
drawLineWithArrowhead(p0,p1,25);
}
function drawLineWithArrowhead(p0,p1,headLength){
var PI=Math.PI;
var degreesInRadians225=225*PI/180;
var degreesInRadians135=135*PI/180;
var dx=p1.x2-p0.x1;
var dy=p1.y2-p0.y1;
var angle=Math.atan2(dy,dx);
// calc arrowhead points
var x225=p1.x2+headLength*Math.cos(angle+degreesInRadians225);
var y225=p1.y2+headLength*Math.sin(angle+degreesInRadians225);
var x135=p1.x2+headLength*Math.cos(angle+degreesInRadians135);
var y135=p1.y2+headLength*Math.sin(angle+degreesInRadians135);
ctx.beginPath();
// draw the line from p0 to p1
ctx.moveTo(p0.x1,p0.y1);
ctx.lineTo(p1.x2,p1.y2);
// draw partial arrowhead at 225 degrees
ctx.moveTo(p1.x2,p1.y2);
ctx.lineTo(x225,y225);
// draw partial arrowhead at 135 degrees
ctx.moveTo(p1.x1,p1.y1);
ctx.lineTo(x135,y135);
// stroke the line and arrowhead
ctx.stroke();
}
canvas {position:absolute;left:0;top:0}
#canvas {background:#eef}
<canvas id="canvas" width=400 height=400></canvas>
<canvas id="tempcanvas" width=400 height=400></canvas>
Example snippet
Sorry out of time (Weekend and all) to write a detailed explanation and no point wasting the code, so hope it helps.
const ctx = canvas.getContext("2d");
ctx.bounds = canvas.getBoundingClientRect();
const P2 = (x = 0, y = 0) => ({x, y});
const points = [];
const lineStyle = "#000";
const nearLineStyle = "#0AF";
const lineWidth = 2;
const nearLineWidth = 3;
const pointStyle = "#000";
const nearPointStyle = "#0AF";
const pointLineWidth = 1;
const nearPointLineWidth = 2;
const arrowSize = 18;
const pointSize = 5;
const nearPointSize = 15;
const checkerSize = 256; // power of two
const checkerCol1 = "#CCC";
const checkerCol2 = "#EEE";
const MIN_SELECT_DIST = 20; // in pixels;
var w = canvas.width, h = canvas.height;
var cw = w / 2, ch = h / 2;
var cursor = "default";
var toolTip = "";
const mouse = { x: 0, y: 0, button: 0 };
const drag = {dragging: false};
requestAnimationFrame(update);
function mouseEvents(e) {
mouse.x = e.pageX - ctx.bounds.left - scrollX;
mouse.y = e.pageY - ctx.bounds.top - scrollY;
if (e.type === "mousedown") { mouse.button |= 1 << (e.which - 1) }
else if (e.type === "mouseup") { mouse.button &= ~(1 << (e.which - 1)) }
}
["down", "up", "move"].forEach(name => document.addEventListener("mouse" + name, mouseEvents));
const checkerboard = (()=> {
const s = checkerSize, s2 = s / 2;
const c = document.createElement("canvas");
c.height = c.width = checkerSize;
const ctx = c.getContext("2d", {alpha: false});
ctx.fillStyle = checkerCol1;
ctx.fillRect(0,0,s, s);
ctx.fillStyle = checkerCol2;
ctx.fillRect(0,0,s2,s2);
ctx.fillRect(s2,s2,s2,s2);
ctx.globalAlpha = 0.25;
var ss = s2;
while(ss > 8) {
ctx.fillStyle = ctx.createPattern(c, "repeat");
ctx.setTransform(1/8,0,0,1/8,0,0);
ctx.fillRect(0,0,s * 8,s * 8);
ss /= 2;
}
return ctx.createPattern(c, "repeat");
})();
function nearestPointLine(points, point, minDist){ // fills nearest object with nearest point and line to point if within minDist.
var i = 0, p1, dist;
nearest.reset(minDist);
const v1 = P2();
const v2 = P2();
const v3 = P2();
for (const p of points) {
v2.x = point.x - p.x;
v2.y = point.y - p.y;
dist = (v2.x * v2.x + v2.y * v2.y) ** 0.5;
if(dist < nearest.point.dist) {
nearest.point.dist = dist;
nearest.point.p = p;
nearest.point.idx = i;
}
if (p1) {
v1.x = p1.x - p.x;
v1.y = p1.y - p.y;
v2.x = point.x - p.x;
v2.y = point.y - p.y;
const u = (v2.x * v1.x + v2.y * v1.y) / (v1.y * v1.y + v1.x * v1.x);
if (u >= 0 && u <= 1) { // is closest poin on line segment
v3.x = p.x + v1.x * u;
v3.y = p.y + v1.y * u;
//ctx.fillRect(v3.x, v3.y, 5, 5)
dist = ((v3.y - point.y) ** 2 + (v3.x - point.x) ** 2) ** 0.5;
if(dist < nearest.line.dist) {
nearest.line.dist = dist;
nearest.line.p1 = p1;
nearest.line.p2 = p;
nearest.line.idx = i;
nearest.line.onLine.x = v3.x;
nearest.line.onLine.y = v3.y;
}
}
}
p1 = p;
i ++;
}
if (nearest.point.idx > -1 && nearest.point.dist / 2 <= nearest.line.dist) {
nearest.active = nearest.point;
nearest.near = true;
} else if (nearest.line.idx > -1) {
nearest.active = nearest.line;
nearest.near = true;
}
}
function drawLine(p1, p2) {
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
}
function drawLineArrow(p1, p2) {
var nx = p1.x - p2.x;
var ny = p1.y - p2.y;
const d =( nx * nx + ny * ny) ** 0.5;
if(d > arrowSize) {
nx /= d;
ny /= d;
ctx.setTransform(-nx, -ny, ny, -nx, p2.x, p2.y);
ctx.beginPath()
ctx.fillStyle = ctx.strokeStyle;
ctx.moveTo(0, 0);
ctx.lineTo(-arrowSize, arrowSize / 2);
ctx.lineTo(-arrowSize, -arrowSize / 2);
ctx.fill();
ctx.setTransform(1,0,0,1,0,0);
}
}
function drawPoint(p, size = pointSize) {
ctx.rect(p.x - size / 2, p.y - size / 2, size, size);
}
function drawLines(points) {
var p1;
ctx.strokeStyle = lineStyle;
ctx.lineWidth = lineWidth;
ctx.beginPath()
for(const p of points) {
if (p1) { drawLine(p1 ,p) }
p1 = p;
}
ctx.stroke();
if(points.length > 1) {
drawLineArrow(points[points.length - 2], p1);
}
}
function drawPoints(points) {
ctx.strokeStyle = pointStyle;
ctx.lineWidth = pointLineWidth;
ctx.beginPath()
for(const p of points) { drawPoint(p) }
ctx.stroke();
}
function sizeCanvas() {
if (w !== innerWidth || h !== innerHeight) {
cw = (w = canvas.width = innerWidth) / 2;
ch = (h = canvas.height = innerHeight) / 2;
ctx.bounds = canvas.getBoundingClientRect();
}
}
const nearest = {
point: { isPoint: true },
line: { onLine: P2() },
reset(minDist) {
nearest.point.dist = minDist;
nearest.point.idx = -1;
nearest.line.dist = minDist;
nearest.line.idx = -1;
nearest.active = null;
nearest.near = false;
},
draw() {
const a = nearest.active;
if (a) {
if (a.isPoint) {
ctx.strokeStyle = nearPointStyle;
ctx.lineWidth = nearPointLineWidth;
ctx.beginPath()
drawPoint(a.p, nearPointSize);
ctx.stroke();
} else {
ctx.strokeStyle = nearLineStyle;
ctx.lineWidth = nearLineWidth;
ctx.beginPath()
drawLine(a.p1, a.p2);
ctx.stroke();
ctx.strokeStyle = nearPointStyle;
ctx.lineWidth = nearPointLineWidth;
ctx.beginPath()
drawPoint(a.onLine, nearPointSize);
ctx.stroke();
}
}
}
}
function update() {
cursor = "crosshair";
toolTip = "";
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
ctx.globalAlpha = 1; // reset alpha
sizeCanvas();
ctx.fillStyle = checkerboard;
ctx.fillRect(0, 0, w, h);
if (!drag.dragging) {
nearestPointLine(points, mouse, MIN_SELECT_DIST);
if (nearest.near && nearest.active.isPoint) { cursor = "move"; toolTip = "Drag to move point"}
else if (nearest.near) { cursor = "crosshair"; toolTip = "Click/drag to cut and drag new point" }
else {
if (points.length < 2) {
cursor = "crosshair";
toolTip ="Click to add point";
} else {
cursor = "default";
toolTip = "";
}
}
}
drawLines(points);
drawPoints(points);
nearest.draw();
if((mouse.button & 1) === 1) {
if (!drag.dragging) {
if(points.length < 2 && !nearest.near) {
points.push(P2(mouse.x, mouse.y));
mouse.button = 0;
} else if (nearest.near) {
if (nearest.active.isPoint) {
drag.point = nearest.active.p;
} else {
drag.point = P2(nearest.active.onLine.x, nearest.active.onLine.y);
points.splice(nearest.active.idx, 0, drag.point);
nearestPointLine(points, drag.point, 20);
}
drag.offX = drag.point.x - mouse.x;
drag.offY = drag.point.y - mouse.y;
drag.dragging = true;
}
}
if(drag.dragging) {
drag.point.x = drag.offX + mouse.x;
drag.point.y = drag.offY + mouse.y;
drag.point.x = drag.point.x < 1 ? 1 : drag.point.x > w - 2 ? w - 2 : drag.point.x;
drag.point.y = drag.point.y < 1 ? 1 : drag.point.y > h - 2 ? h - 2 : drag.point.y;
cursor = "none";
}
} else if((mouse.button & 1) === 0) {
drag.dragging = false;
drag.point = null;
}
canvas.title = toolTip;
canvas.style.cursor = cursor;
requestAnimationFrame(update);
}
canvas {
position: absolute;
top: 0px;
left: 0px;
}
<canvas id="canvas"></canvas>

I need to make this canvas transparent but none of the solutions are working

I have tried all the jQuery tricks as well as the CSS tricks, but none of them work.. I don't really know anything about <canvas> but I've been trying to solve this for a day now.. can anybody help?
I am trying not mess up the code and just make the black background transparent so that I could use this canvas over a carousal..
// helper functions
const PI2 = Math.PI * 2
const random = (min, max) => Math.random() * (max - min + 1) + min | 0
const timestamp = _ => new Date().getTime()
// container
class Birthday {
constructor() {
this.resize()
// create a lovely place to store the firework
this.fireworks = []
this.counter = 0
}
resize() {
this.width = canvas.width = window.innerWidth
let center = this.width / 2 | 0
this.spawnA = center - center / 4 | 0
this.spawnB = center + center / 4 | 0
this.height = canvas.height = window.innerHeight
this.spawnC = this.height * .1
this.spawnD = this.height * .5
}
onClick(evt) {
let x = evt.clientX || evt.touches && evt.touches[0].pageX
let y = evt.clientY || evt.touches && evt.touches[0].pageY
let count = random(3, 5)
for (let i = 0; i < count; i++) this.fireworks.push(new Firework(
random(this.spawnA, this.spawnB),
this.height,
x,
y,
random(0, 260),
random(30, 110)))
this.counter = -1
}
update(delta) {
ctx.globalCompositeOperation = 'hard-light'
ctx.fillStyle = `rgba(20,20,20,${ 7 * delta })`
ctx.fillRect(0, 0, this.width, this.height)
ctx.globalCompositeOperation = 'lighter'
for (let firework of this.fireworks) firework.update(delta)
// if enough time passed... create new new firework
this.counter += delta * 3 // each second
if (this.counter >= 1) {
this.fireworks.push(new Firework(
random(this.spawnA, this.spawnB),
this.height,
random(0, this.width),
random(this.spawnC, this.spawnD),
random(0, 360),
random(30, 110)))
this.counter = 0
}
// remove the dead fireworks
if (this.fireworks.length > 1000) this.fireworks = this.fireworks.filter(firework => !firework.dead)
}
}
class Firework {
constructor(x, y, targetX, targetY, shade, offsprings) {
this.dead = false
this.offsprings = offsprings
this.x = x
this.y = y
this.targetX = targetX
this.targetY = targetY
this.shade = shade
this.history = []
}
update(delta) {
if (this.dead) return
let xDiff = this.targetX - this.x
let yDiff = this.targetY - this.y
if (Math.abs(xDiff) > 3 || Math.abs(yDiff) > 3) { // is still moving
this.x += xDiff * 2 * delta
this.y += yDiff * 2 * delta
this.history.push({
x: this.x,
y: this.y
})
if (this.history.length > 20) this.history.shift()
} else {
if (this.offsprings && !this.madeChilds) {
let babies = this.offsprings / 2
for (let i = 0; i < babies; i++) {
let targetX = this.x + this.offsprings * Math.cos(PI2 * i / babies) | 0
let targetY = this.y + this.offsprings * Math.sin(PI2 * i / babies) | 0
birthday.fireworks.push(new Firework(this.x, this.y, targetX, targetY, this.shade, 0))
}
}
this.madeChilds = true
this.history.shift()
}
if (this.history.length === 0) this.dead = true
else if (this.offsprings) {
for (let i = 0; this.history.length > i; i++) {
let point = this.history[i]
ctx.beginPath()
ctx.fillStyle = 'hsl(' + this.shade + ',100%,' + i + '%)'
ctx.arc(point.x, point.y, 1, 0, PI2, false)
ctx.fill()
}
} else {
ctx.beginPath()
ctx.fillStyle = 'hsl(' + this.shade + ',100%,50%)'
ctx.arc(this.x, this.y, 1, 0, PI2, false)
ctx.fill()
}
}
}
let canvas = document.getElementById('birthday')
let ctx = canvas.getContext('2d')
let then = timestamp()
let birthday = new Birthday
window.onresize = () => birthday.resize()
document.onclick = evt => birthday.onClick(evt)
document.ontouchstart = evt => birthday.onClick(evt)
;
(function loop() {
requestAnimationFrame(loop)
let now = timestamp()
let delta = now - then
then = now
birthday.update(delta / 1000)
})()
<canvas id="birthday"></canvas>
All you need to do is replace fillRect with clearRect in the update method of the Birthday class like this:
ctx.clearRect(0, 0, this.width, this.height)
You may need to make further adjustments to the color of the firework trail though, since it seems like it was supposed to match the background color.
If your canvas still isn't transparent, check your css to ensure that you're not setting the background color that way.
const PI2 = Math.PI * 2
const random = (min, max) => Math.random() * (max - min + 1) + min | 0
const timestamp = _ => new Date().getTime()
// container
class Birthday {
constructor() {
this.resize()
// create a lovely place to store the firework
this.fireworks = []
this.counter = 0
}
resize() {
this.width = canvas.width = window.innerWidth
let center = this.width / 2 | 0
this.spawnA = center - center / 4 | 0
this.spawnB = center + center / 4 | 0
this.height = canvas.height = window.innerHeight
this.spawnC = this.height * .1
this.spawnD = this.height * .5
}
onClick(evt) {
let x = evt.clientX || evt.touches && evt.touches[0].pageX
let y = evt.clientY || evt.touches && evt.touches[0].pageY
let count = random(3, 5)
for (let i = 0; i < count; i++) this.fireworks.push(new Firework(
random(this.spawnA, this.spawnB),
this.height,
x,
y,
random(0, 260),
random(30, 110)))
this.counter = -1
}
update(delta) {
ctx.globalCompositeOperation = 'hard-light'
ctx.fillStyle = `rgba(20,20,20,${ 7 * delta })`
ctx.clearRect(0, 0, this.width, this.height)
ctx.globalCompositeOperation = 'lighter'
for (let firework of this.fireworks) firework.update(delta)
// if enough time passed... create new new firework
this.counter += delta * 3 // each second
if (this.counter >= 1) {
this.fireworks.push(new Firework(
random(this.spawnA, this.spawnB),
this.height,
random(0, this.width),
random(this.spawnC, this.spawnD),
random(0, 360),
random(30, 110)))
this.counter = 0
}
// remove the dead fireworks
if (this.fireworks.length > 1000) this.fireworks = this.fireworks.filter(firework => !firework.dead)
}
}
class Firework {
constructor(x, y, targetX, targetY, shade, offsprings) {
this.dead = false
this.offsprings = offsprings
this.x = x
this.y = y
this.targetX = targetX
this.targetY = targetY
this.shade = shade
this.history = []
}
update(delta) {
if (this.dead) return
let xDiff = this.targetX - this.x
let yDiff = this.targetY - this.y
if (Math.abs(xDiff) > 3 || Math.abs(yDiff) > 3) { // is still moving
this.x += xDiff * 2 * delta
this.y += yDiff * 2 * delta
this.history.push({
x: this.x,
y: this.y
})
if (this.history.length > 20) this.history.shift()
} else {
if (this.offsprings && !this.madeChilds) {
let babies = this.offsprings / 2
for (let i = 0; i < babies; i++) {
let targetX = this.x + this.offsprings * Math.cos(PI2 * i / babies) | 0
let targetY = this.y + this.offsprings * Math.sin(PI2 * i / babies) | 0
birthday.fireworks.push(new Firework(this.x, this.y, targetX, targetY, this.shade, 0))
}
}
this.madeChilds = true
this.history.shift()
}
if (this.history.length === 0) this.dead = true
else if (this.offsprings) {
for (let i = 0; this.history.length > i; i++) {
let point = this.history[i]
ctx.beginPath()
ctx.fillStyle = 'hsl(' + this.shade + ',100%,' + i + '%)'
ctx.arc(point.x, point.y, 1, 0, PI2, false)
ctx.fill()
}
} else {
ctx.beginPath()
ctx.fillStyle = 'hsl(' + this.shade + ',100%,50%)'
ctx.arc(this.x, this.y, 1, 0, PI2, false)
ctx.fill()
}
}
}
let canvas = document.getElementById('birthday')
let ctx = canvas.getContext('2d')
let then = timestamp()
let birthday = new Birthday
window.onresize = () => birthday.resize()
document.onclick = evt => birthday.onClick(evt)
document.ontouchstart = evt => birthday.onClick(evt)
;
(function loop() {
requestAnimationFrame(loop)
let now = timestamp()
let delta = now - then
then = now
birthday.update(delta / 1000)
})()
div {
height : 100vh;
width : 100vw;
display : flex;
flex-direction : center;
align-items : center;
justify-content : center;
}
canvas {
position : absolute;
top : 0;
left : 0;
}
<div>Content Underneath</div>
<canvas id="birthday"></canvas>

HTML5 Canvas Scallop Shape

I really need help badly on how to create a scallop shape using Canvas
I tried playing around the cloud sample but it was really difficult for me to create what I've wanted.
I simply wanted to know the code for the scallop shape for rectangle and circle.
This is the image that What I've wanted.
It design doesn't have to exactly the same but as possible it does look like this.
THANK YOU SO MUCH IN ADVANCEEE..
You can draw such a shape by using dotted line dash, like this(a bit tricky).
JavaScript:
const canvas = document.querySelector("#canvas");
canvas.width = canvas.height = 300;
const ctx = canvas.getContext("2d");
const rect = [50, 50, 200, 200];
//draw dotted line dash.
ctx.lineCap = "round";
ctx.setLineDash([0, 40]);
ctx.lineDashOffset = 20;
ctx.lineWidth = 42;
ctx.strokeStyle = "purple";
ctx.strokeRect(...rect);
//remove disuse range.
ctx.globalCompositeOperation = "destination-out";
ctx.lineWidth = 38;
ctx.strokeRect(...rect);
ctx.fillRect(...rect);
Demo:
http://jsdo.it/defghi1977/iFR7
From an older answer but the question was very vague and has a lot of extra baggage. Here is a snippet from that answer. It has some extra code in it that may be helpful but not directly related.
The function display (about halfway down) does most of the work, adding the arcs to the object box.
See running demo for instruction
const pointSize = 4;
const pointCol = "#4AF";
var arcDepth = -0.5; // depth of arc as a factor of line seg length
// Note to have arc go the other (positive) way you have
// to change the ctx.arc draw call by adding anticlockwise flag
// see drawArc for more
const arcCol = "#F92";
const arcWidth = 8;
// Find a circle that fits 3 points.
function fitCircleTo3P(p1x, p1y, p2x, p2y, p3x, p3y, arc) {
var vx,
vy,
c,
c1,
u;
c = (p2x - p1x) / (p1y - p2y); // slope of vector from vec 1 to vec 2
c1 = (p3x - p2x) / (p2y - p3y); // slope of vector from vec 2 to vec 3
// This will not happen in this example
if (c === c1) { // if slope is the same they must be on the same line
return null; // points are in a line
}
// locate the center
if (p1y === p2y) { // special case with p1 and p2 have same y
vx = (p1x + p2x) / 2;
vy = c1 * vx + (((p2y + p3y) / 2) - c1 * ((p2x + p3x) / 2));
} else
if (p2y === p3y) { // special case with p2 and p3 have same y
vx = (p2x + p3x) / 2;
vy = c * vx + (((p1y + p2y) / 2) - c * ((p1x + p2x) / 2));
} else {
vx = ((((p2y + p3y) / 2) - c1 * ((p2x + p3x) / 2)) - (u = ((p1y + p2y) / 2) - c * ((p1x + p2x) / 2))) / (c - c1);
vy = c * vx + u;
}
arc.x = vx;
arc.y = vy;
vx = p1x - vx;
vy = p1y - vy;
arc.rad = Math.sqrt(vx * vx + vy * vy);
return arc;
}
var points = [];
var arcs = [];
function addArc(p1, p2, depth) {
var arc = {
p1 : p1,
p2 : p2,
depth : depth,
rad : null, // radius
a1 : null, // angle from
a2 : null, // angle to
x : null,
y : null,
}
arcs.push(arc);
return arc;
}
function calcArc(arc, depth) {
var p = points[arc.p1]; // get points
var pp = points[arc.p2];
// change depth if needed
depth = arc.depth = depth !== undefined ? depth : arc.depth;
var vx = pp[0] - p[0]; // vector from p to pp
var vy = pp[1] - p[1];
var cx = (pp[0] + p[0]) / 2; // center point
var cy = (pp[1] + p[1]) / 2; // center point
var len = Math.sqrt(vx * vx + vy * vy); // get length
cx -= vy * depth; // find 3 point at 90 deg to line and dist depth
cy += vx * depth;
// To have depth as a fixed length uncomment 4 lines below and comment out 2 lines above.
//var nx = vx / len; // normalise vector
//var ny = vy / len;
//cx -= ny * depth; // find 3 point at 90 deg to line and dist depth
//cy += nx * depth;
fitCircleTo3P(p[0], p[1], cx, cy, pp[0], pp[1], arc); // get the circle that fits
arc.a1 = Math.atan2(p[1] - arc.y, p[0] - arc.x); // get angle from circle center to first point
arc.a2 = Math.atan2(pp[1] - arc.y, pp[0] - arc.x); // get angle from circle center to second point
}
function addPoint(x, y) {
points.push([x, y]);
}
function drawPoint(x, y, size, col) {
ctx.fillStyle = col;
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fill();
}
function drawArcStart(width,col){
ctx.lineCap = "round";
ctx.strokeStyle = col;
ctx.lineJoin = "round";
ctx.lineWidth = width;
ctx.beginPath();
}
function drawArc(arc){
ctx.arc(arc.x,arc.y,arc.rad,arc.a1,arc.a2);
}
function drawArcDone(){
ctx.closePath();
ctx.stroke();
}
function findClosestPoint(x, y, dist) {
var index = -1;
for (var i = 0; i < points.length; i++) {
var p = points[i];
var vx = x - p[0];
var vy = y - p[1];
var d = Math.sqrt(vx * vx + vy * vy);
if (d < dist) {
dist = d;
index = i;
}
}
return index;
}
var dragging = false;
var drag = -1;
var dragX, dragY;
var recalcArcs = false;
var box;
//========================================================================
// New box code from here down
// creates the box when canvas is ready
var onResize = function(){
box = {
x : canvas.width * (1/8),
y : canvas.height * (1/8),
w : canvas.width * (6/8),
h : canvas.height * (6/8),
recalculate : true,
arcCount : 20, // number of arcs to try and fit. Does not mean that it will happen
}
}
function display() {
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
ctx.globalAlpha = 1; // reset alpha
ctx.clearRect(0, 0, w, h);
if(mouse.w !== 0){
if(mouse.buttonRaw & 4){ // change arc depth
if(mouse.w < 0){
arcDepth *= 1/1.05;
}else{
arcDepth *= 1.05;
}
recalcArcs = true;
}else{ // change arc count
box.arcCount += Math.sign(mouse.w);
box.arcCount = Math.max(4,box.arcCount);
box.recalculate = true;
}
mouse.w = 0;
}
// drag out box;
if(mouse.buttonRaw & 1){
if(!dragging){
box.x = mouse.x;
box.y = mouse.y;
dragging = true;
}
box.w = mouse.x - box.x;
box.h = mouse.y - box.y;
box.recalculate = true;
if(box.w <0){
box.x = box.x + box.w;
box.w = - box.w;
}
if(box.h <0){
box.y = box.y + box.h;
box.h = - box.h;
}
}else{
dragging = false;
}
// stop error
if(box.w === 0 || box.h === 0){
box.recalculate = false;
}
// calculate box arcs
if(box.recalculate){
// reset arrays
points.length = 0;
arcs.length = 0;
// get perimeter length
var perimLen = (box.w + box.h)* 2;
// get estimated step size
var step = perimLen / box.arcCount;
// get inset size for width and hight
var wInStep = (box.w - (Math.floor(box.w/step)-1)*step) / 2;
var hInStep = (box.h - (Math.floor(box.h/step)-1)*step) / 2;
// fix if box to narrow
if(box.w < step){
wInStep = 0;
hInStep = 0;
step = box.h / (Math.floor(box.h/step));
}else if(box.h < step){
wInStep = 0;
hInStep = 0;
step = box.w / (Math.floor(box.w/step));
}
// Add points clock wise
var x = box.x + wInStep;
while(x < box.x + box.w){ // across top
addPoint(x,box.y);
x += step;
}
var y = box.y + hInStep;
while(y < box.y + box.h){ // down right side
addPoint(box.x + box.w,y);
y += step;
}
x = box.x + box.w - wInStep;
while(x > box.x){ // left along bottom
addPoint(x,box.y + box.h);
x -= step;
}
var y = box.y + box.h - hInStep;
while(y > box.y){ // up along left side
addPoint(box.x,y);
y -= step;
}
// calculate arcs.
for(var i =0; i <points.length; i++){
calcArc(addArc(i,(i + 1) % points.length,arcDepth));
}
box.recalculate = false;
}
// recalculate arcs if needed
for(var i = 0; i < arcs.length; i ++){
if(recalcArcs){
calcArc(arcs[i],arcDepth);
}
}
// draw arcs
drawArcStart(arcWidth,arcCol)
for(var i = 0; i < arcs.length; i ++){
drawArc(arcs[i]);
}
drawArcDone();
recalcArcs = false;
}
//===========================================================================================
// END OF ANSWER
// Boiler plate code from here down. Does mouse,canvas,resize and what not
var w, h, cw, ch, canvas, ctx, mouse, globalTime = 0, firstRun = true; ;
(function () {
const RESIZE_DEBOUNCE_TIME = 100;
var createCanvas,
resizeCanvas,
setGlobals,
resizeCount = 0;
createCanvas = function () {
var c,
cs;
cs = (c = document.createElement("canvas")).style;
cs.position = "absolute";
cs.top = cs.left = "0px";
cs.zIndex = 1000;
document.body.appendChild(c);
return c;
}
resizeCanvas = function () {
if (canvas === undefined) {
canvas = createCanvas();
}
canvas.width = innerWidth;
canvas.height = innerHeight;
ctx = canvas.getContext("2d");
if (typeof setGlobals === "function") {
setGlobals();
}
if (typeof onResize === "function") {
if (firstRun) {
onResize();
firstRun = false;
} else {
resizeCount += 1;
setTimeout(debounceResize, RESIZE_DEBOUNCE_TIME);
}
}
}
function debounceResize() {
resizeCount -= 1;
if (resizeCount <= 0) {
onResize();
}
}
setGlobals = function () {
cw = (w = canvas.width) / 2;
ch = (h = canvas.height) / 2;
}
mouse = (function () {
function preventDefault(e) {
e.preventDefault();
}
var mouse = {
x : 0,
y : 0,
w : 0,
alt : false,
shift : false,
ctrl : false,
buttonRaw : 0,
over : false,
bm : [1, 2, 4, 6, 5, 3],
active : false,
bounds : null,
crashRecover : null,
mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",")
};
var m = mouse;
function mouseMove(e) {
var t = e.type;
m.bounds = m.element.getBoundingClientRect();
m.x = e.pageX - m.bounds.left;
m.y = e.pageY - m.bounds.top;
m.alt = e.altKey;
m.shift = e.shiftKey;
m.ctrl = e.ctrlKey;
if (t === "mousedown") {
m.buttonRaw |= m.bm[e.which - 1];
} else if (t === "mouseup") {
m.buttonRaw &= m.bm[e.which + 2];
} else if (t === "mouseout") {
m.buttonRaw = 0;
m.over = false;
} else if (t === "mouseover") {
m.over = true;
} else if (t === "mousewheel") {
m.w = e.wheelDelta;
} else if (t === "DOMMouseScroll") {
m.w = -e.detail;
}
e.preventDefault();
}
m.start = function (element) {
if (m.element !== undefined) {
m.removeMouse();
}
m.element = element === undefined ? document : element;
m.mouseEvents.forEach(n => {
m.element.addEventListener(n, mouseMove);
});
m.element.addEventListener("contextmenu", preventDefault, false);
m.active = true;
}
m.remove = function () {
if (m.element !== undefined) {
m.mouseEvents.forEach(n => {
m.element.removeEventListener(n, mouseMove);
});
m.element.removeEventListener("contextmenu", preventDefault);
m.element = m.callbacks = undefined;
m.active = false;
}
}
return mouse;
})();
function update(timer) { // Main update loop
if (ctx === undefined) {
return;
}
globalTime = timer;
display(); // call demo code
requestAnimationFrame(update);
}
setTimeout(function () {
resizeCanvas();
mouse.start(canvas, true);
window.addEventListener("resize", resizeCanvas);
requestAnimationFrame(update);
}, 0);
})();
Left click drag to create a box<br>Mouse wheel to change arc count<br>Hold right button down and wheel to change arc depth.<br>
Use https://www.w3schools.com/tags/canvas_beziercurveto.asp "Bezier Curve Method" to make complicated shapes.
I suggest going on desmos and messing around with the bezier curve in order to understand the complications. I hope this helped :)
Edit: Bezier curves work like this:
ctx.bezierCurveTo(Control point x, control point y, 2nd control point x, 2nd control point y, finishing x, finishing y);

Categories

Resources