可拖动 HTML div 在缩放 in/out 时不会停留在原位。我怎样才能解决这个问题?

Draggable HTML div doesn't stay in place when zooming in/out. How can I fix this?

我正在尝试创建一个基本的颜色选择器,当我在 canvas 渐变上拖动标记时,它会更改页面的背景颜色。

该程序的行为符合我目前的预期。但是,在拖动它之后,当我在浏览器上放大或缩小时,标记不会停留在原位。

我尝试添加一个 div 作为颜色选择器 canvas 和标记的相对位置的包装器。这阻止了标记选择 canvas 上的颜色,所以我删除了它。

我也尝试将标记附加到 canvas 而不是容器,但它随后消失了。

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 class="container">
        <canvas width="300px" height="300px" class="colorPickerCanvas"></canvas>
        <canvas width="40px" height="300px" class="colorSlider"></canvas>
    </div>  
    <script src='script.js'></script>
</body>
</html>

对于我的代码的其他方面的任何反馈或建设性批评,我将不胜感激!

将样式 max-width: 400px; 添加到 body 有效:

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 class="container">
        <canvas width="300px" height="300px" class="colorPickerCanvas"></canvas>
        <canvas width="40px" height="300px" class="colorSlider"></canvas>
    </div>  
    <script src='script.js'></script>
</body>
</html>