I'm trying to create a basic color picker that changes the background color of the page when I drag a marker on the canvas gradient.
The program behaves as expected with what I have so far. But, after dragging it, the marker doesn't stay in place when I zoom in or out on the browser.
I tried adding a div as a wrapper with relative position for the color picker canvas and the marker. This prevented the marker from picking the colors on the canvas, so I removed it.
I also tried appending the marker to the canvas instead of the container, but then it disappears.
const container = document.querySelector('.container');
const colorPickerCanvas = document.querySelector('.colorPickerCanvas');
const colorSlider = document.querySelector('.colorSlider');
const marker = document.createElement('div');
marker.classList.add('marker');
marker.setAttribute('draggable', true);
container.appendChild(marker)
//ADD 2D CONTEXT TO COLOR PICKER CANVAS
let colorPickerCtx = colorPickerCanvas.getContext('2d');
var color = 'blue';
var dragging = false;
//CREATE A HORIZONTAL GRADIENT ON THE CANVAS
let horizontalGradient = colorPickerCtx.createLinearGradient(0, 0, 300, 0);
horizontalGradient.addColorStop(0, 'white');
horizontalGradient.addColorStop(1, color);
colorPickerCtx.fillStyle = horizontalGradient;
colorPickerCtx.fillRect(0, 0, 300, 300);
//CREATE A VERTICAL GRADIENT ON THE CANVAS
let verticalGradient = colorPickerCtx.createLinearGradient(0, 0, 0, 300);
verticalGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
verticalGradient.addColorStop(1, 'black');
colorPickerCtx.fillStyle = verticalGradient;
colorPickerCtx.fillRect(0, 0, 300, 300);
colorPickerCanvas.addEventListener('click', (event) => {
event.preventDefault()
//GET THE COORDINATES OF CLICKED PIXEL
let xCoordinates = event.pageX - colorPickerCanvas.offsetLeft;
let yCoordinates = event.pageY - colorPickerCanvas.offsetTop;
console.log('X coordinates are: ' xCoordinates ' and Y coordinates are: ' yCoordinates);
//GET RGB VALUES OF CLICKED PIXEL
let imgData = colorPickerCtx.getImageData(xCoordinates, yCoordinates, 1, 1);
ctxR = imgData.data[0];
ctxG = imgData.data[1];
ctxB = imgData.data[2];
console.log('Blue value is: ' ctxB)
//PLACE MARKER WHERE MOUSE IS CLICKED ON CANVAS
marker.style.top = event.pageY - 15 'px';
marker.style.left = event.pageX - 15 'px';
document.body.style.backgroundColor = `rgb(${ctxR}, ${ctxG}, ${ctxB})`
});
marker.addEventListener('dragstart', () => {
dragging = true;
});
colorPickerCanvas.addEventListener('dragover', (event) => {
if (dragging) {
//GET COORDINATES OF MARKER WHILE BEING DRAGGED
let xCoordinates = event.pageX - colorPickerCanvas.offsetLeft;
let yCoordinates = event.pageY - colorPickerCanvas.offsetTop;
//CHANGE THE BACKGROUND COLOR WHILE MARKER IS DRAGGED
let imgData = colorPickerCtx.getImageData(xCoordinates, yCoordinates, 1, 1);
ctxR = imgData.data[0];
ctxG = imgData.data[1];
ctxB = imgData.data[2];
document.body.style.backgroundColor = `rgb(${ctxR}, ${ctxG}, ${ctxB})`
};
});
marker.addEventListener('dragend', (event) => {
dragging = false;
//DROP THE MARKER WHERE DRAGGING STOPS
marker.style.top = event.pageY - 8 'px';
marker.style.left = event.pageX - 8 'px';
})
//ADD 2D CONTEXT TO COLOR SLIDER
let colorSliderCtx = colorSlider.getContext('2d');
//CREATE A VERTICAL GRADIENT ON THE COLOR SLIDER
let sliderGradient = colorSliderCtx.createLinearGradient(0, 0, 0, 300);
sliderGradient.addColorStop(0, 'red');
sliderGradient.addColorStop(0.1, 'orange');
sliderGradient.addColorStop(0.2, 'yellow');
sliderGradient.addColorStop(0.4, 'lime');
sliderGradient.addColorStop(0.5, 'skyblue');
sliderGradient.addColorStop(0.7, 'blue');
sliderGradient.addColorStop(0.9, 'magenta');
sliderGradient.addColorStop(1, 'red');
colorSliderCtx.fillStyle = sliderGradient;
colorSliderCtx.fillRect(0, 0, 40, 300);
colorSlider.addEventListener('click', (event) => {
//GET THE COORDINATES OF CLICKED PIXEL
let sliderX = event.pageX - colorSlider.offsetLeft;
let sliderY = event.pageY - colorSlider.offsetTop;
console.log(sliderX)
//GET RGB VALUES OF CLICKED PIXEL
let sliderImgData = colorSliderCtx.getImageData(sliderX, sliderY, 1, 1);
sliderR = sliderImgData.data[0];
sliderG = sliderImgData.data[1];
sliderB = sliderImgData.data[2];
let color = `rgb(${sliderR}, ${sliderG}, ${sliderB})`
//CREATE A HORIZONTAL GRADIENT ON THE CANVAS
let horizontalGradient = colorPickerCtx.createLinearGradient(0, 0, 300, 0);
horizontalGradient.addColorStop(0, 'white');
horizontalGradient.addColorStop(1, color);
colorPickerCtx.fillStyle = horizontalGradient;
colorPickerCtx.fillRect(0, 0, 300, 300);
//CREATE A VERTICAL GRADIENT ON THE CANVAS
let verticalGradient = colorPickerCtx.createLinearGradient(0, 0, 0, 300);
verticalGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
verticalGradient.addColorStop(1, 'black');
colorPickerCtx.fillStyle = verticalGradient;
colorPickerCtx.fillRect(0, 0, 300, 300);
//PLACE MARKER WHERE MOUSE IS CLICKED ON SLIDER
});
.container {
display: flex;
justify-content: center;
gap: 16px;
position: relative;
}
.colorPickerCanvas {
position: relative;
align-self: flex-start;
}
.marker {
position: absolute;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0);
border-style: solid;
width: 8px;
height: 8px;
}
.colorSlider {
align-self: flex-start;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Color Picker</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div >
<canvas width="300px" height="300px" ></canvas>
<canvas width="40px" height="300px" ></canvas>
</div>
<script src='script.js'></script>
</body>
</html>
I'll appreciate any feedback or constructive criticism on other aspects of my code as well!
CodePudding user response:
Adding the styling max-width: 400px;
onto body
worked:
const container = document.querySelector('.container');
const colorPickerCanvas = document.querySelector('.colorPickerCanvas');
const colorSlider = document.querySelector('.colorSlider');
const marker = document.createElement('div');
marker.classList.add('marker');
marker.setAttribute('draggable', true);
container.appendChild(marker)
//ADD 2D CONTEXT TO COLOR PICKER CANVAS
let colorPickerCtx = colorPickerCanvas.getContext('2d');
var color = 'blue';
var dragging = false;
//CREATE A HORIZONTAL GRADIENT ON THE CANVAS
let horizontalGradient = colorPickerCtx.createLinearGradient(0, 0, 300, 0);
horizontalGradient.addColorStop(0, 'white');
horizontalGradient.addColorStop(1, color);
colorPickerCtx.fillStyle = horizontalGradient;
colorPickerCtx.fillRect(0, 0, 300, 300);
//CREATE A VERTICAL GRADIENT ON THE CANVAS
let verticalGradient = colorPickerCtx.createLinearGradient(0, 0, 0, 300);
verticalGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
verticalGradient.addColorStop(1, 'black');
colorPickerCtx.fillStyle = verticalGradient;
colorPickerCtx.fillRect(0, 0, 300, 300);
colorPickerCanvas.addEventListener('click', (event) => {
event.preventDefault()
//GET THE COORDINATES OF CLICKED PIXEL
let xCoordinates = event.pageX - colorPickerCanvas.offsetLeft;
let yCoordinates = event.pageY - colorPickerCanvas.offsetTop;
console.log('X coordinates are: ' xCoordinates ' and Y coordinates are: ' yCoordinates);
//GET RGB VALUES OF CLICKED PIXEL
let imgData = colorPickerCtx.getImageData(xCoordinates, yCoordinates, 1, 1);
ctxR = imgData.data[0];
ctxG = imgData.data[1];
ctxB = imgData.data[2];
console.log('Blue value is: ' ctxB)
//PLACE MARKER WHERE MOUSE IS CLICKED ON CANVAS
marker.style.top = event.pageY - 15 'px';
marker.style.left = event.pageX - 15 'px';
document.body.style.backgroundColor = `rgb(${ctxR}, ${ctxG}, ${ctxB})`
});
marker.addEventListener('dragstart', () => {
dragging = true;
});
colorPickerCanvas.addEventListener('dragover', (event) => {
if (dragging) {
//GET COORDINATES OF MARKER WHILE BEING DRAGGED
let xCoordinates = event.pageX - colorPickerCanvas.offsetLeft;
let yCoordinates = event.pageY - colorPickerCanvas.offsetTop;
//CHANGE THE BACKGROUND COLOR WHILE MARKER IS DRAGGED
let imgData = colorPickerCtx.getImageData(xCoordinates, yCoordinates, 1, 1);
ctxR = imgData.data[0];
ctxG = imgData.data[1];
ctxB = imgData.data[2];
document.body.style.backgroundColor = `rgb(${ctxR}, ${ctxG}, ${ctxB})`
};
});
marker.addEventListener('dragend', (event) => {
dragging = false;
//DROP THE MARKER WHERE DRAGGING STOPS
marker.style.top = event.pageY - 8 'px';
marker.style.left = event.pageX - 8 'px';
})
//ADD 2D CONTEXT TO COLOR SLIDER
let colorSliderCtx = colorSlider.getContext('2d');
//CREATE A VERTICAL GRADIENT ON THE COLOR SLIDER
let sliderGradient = colorSliderCtx.createLinearGradient(0, 0, 0, 300);
sliderGradient.addColorStop(0, 'red');
sliderGradient.addColorStop(0.1, 'orange');
sliderGradient.addColorStop(0.2, 'yellow');
sliderGradient.addColorStop(0.4, 'lime');
sliderGradient.addColorStop(0.5, 'skyblue');
sliderGradient.addColorStop(0.7, 'blue');
sliderGradient.addColorStop(0.9, 'magenta');
sliderGradient.addColorStop(1, 'red');
colorSliderCtx.fillStyle = sliderGradient;
colorSliderCtx.fillRect(0, 0, 40, 300);
colorSlider.addEventListener('click', (event) => {
//GET THE COORDINATES OF CLICKED PIXEL
let sliderX = event.pageX - colorSlider.offsetLeft;
let sliderY = event.pageY - colorSlider.offsetTop;
console.log(sliderX)
//GET RGB VALUES OF CLICKED PIXEL
let sliderImgData = colorSliderCtx.getImageData(sliderX, sliderY, 1, 1);
sliderR = sliderImgData.data[0];
sliderG = sliderImgData.data[1];
sliderB = sliderImgData.data[2];
let color = `rgb(${sliderR}, ${sliderG}, ${sliderB})`
//CREATE A HORIZONTAL GRADIENT ON THE CANVAS
let horizontalGradient = colorPickerCtx.createLinearGradient(0, 0, 300, 0);
horizontalGradient.addColorStop(0, 'white');
horizontalGradient.addColorStop(1, color);
colorPickerCtx.fillStyle = horizontalGradient;
colorPickerCtx.fillRect(0, 0, 300, 300);
//CREATE A VERTICAL GRADIENT ON THE CANVAS
let verticalGradient = colorPickerCtx.createLinearGradient(0, 0, 0, 300);
verticalGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
verticalGradient.addColorStop(1, 'black');
colorPickerCtx.fillStyle = verticalGradient;
colorPickerCtx.fillRect(0, 0, 300, 300);
//PLACE MARKER WHERE MOUSE IS CLICKED ON SLIDER
});
body {
max-width: 400px;
}
.container {
display: flex;
justify-content: center;
gap: 16px;
position: relative;
}
.colorPickerCanvas {
position: relative;
align-self: flex-start;
}
.marker {
position: absolute;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0);
border-style: solid;
width: 8px;
height: 8px;
}
.colorSlider {
align-self: flex-start;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Color Picker</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div >
<canvas width="300px" height="300px" ></canvas>
<canvas width="40px" height="300px" ></canvas>
</div>
<script src='script.js'></script>
</body>
</html>