The canvas is either displayed solely on the first image of the slider or attached to the bottom of every image

While attempting to implement a feature where clicking on an image would draw a circle on a canvas overlaying it, I encountered an issue. When applying

cnvs.style.position = 'absolute';
, all canvas elements stack on top of each other instead of being overlaid on their respective images. If I click on multiple images, the circle is only drawn on the first image. Conversely, if I remove
cnvs.style.position = 'absolute';
, the canvas connects to the bottom of the image instead of overlaying it. My goal is to ensure that each canvas and image are properly overlaid so that clicking on any image displays a circle. This seems to be a CSS-related problem that I'm struggling to resolve.

document.body.onload = addElement;

      function addElement() {
            
            // image path
            const imagePath = ['https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fen%2F8%2F84%2FAssociation_of_Gay_and_Lesbian_Psychiatrists_logo.jpg&f=1&nofb=1', 'https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fstatic01.nyt.com%2Fnewsgraphics%2F2016%2F07%2F14%2Fpluto-one-year%2Fassets%2Ficon-pluto.png&f=1&nofb=1', 'https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse4.mm.bing.net%2Fth%3Fid%3DOIP.oFxADNN67dYP-ke5xg7HbQHaHG%26pid%3DApi&f=1', 'https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fmedia.glassdoor.com%2Fsqll%2F1065746%2Felevation-church-squarelogo-1453223965790.png&f=1&nofb=1'];

            for (const image of imagePath) {

                  var slice = image.slice(26, 34);
                  var id = image;
                  var hdnName = document.getElementById("sendServ"); 

                  const img = document.createElement("img");
                  img.src = image;
                  img.classList.add("new");
                  img.id = slice;

                  const cnvs = document.createElement("canvas");
                  cnvs.classList.add("suiteiCanvas");

                  cnvs.style.left = img.offsetLeft + "px";
                  cnvs.style.top = img.offsetTop + "px";
                  cnvs.style.display = 'none';

                  var ctx = cnvs.getContext("2d");
                  ctx.clearRect(0, 0, cnvs.width, cnvs.height);
                  ctx.beginPath();
                  ctx.arc(100, 75, 50, 0, 2 * Math.PI, false);
                  ctx.lineWidth = 15;
                  ctx.strokeStyle = '#FF0000';
                  ctx.stroke();

                  var div = document.createElement("div");
                  var div1 = document.createElement("div");
                  div.id = id;
                  div1.id = '1';
                  div.classList.add("image");


                  img.onclick = function draw() {
                        cnvs.style.display = '';
                        hdnName.value = img.id;
                  };

                  cnvs.onclick = function remove() {
                        cnvs.style.display = 'none';
                        hdnName.value = null;
                  };

                  document.getElementById('suitei-slider').appendChild(div);

                  document.getElementById(image).appendChild(img);
                  document.getElementById(image).appendChild(cnvs);


            }
      }

// slick slider      
   
canvas.suiteiCanvas{
  height: auto; 
  width: auto;
  
max-height: 200px;
max-width: 150px;

margin-left: 100px; 
margin-right: 100px;
border:3px solid rgb(20, 11, 11);
}

#draw-btn {
  font-size: 14px;
  padding: 2px 16px 3px 16px;
  margin-bottom: 8px;
}

img.new {


  height: auto; 
  width: auto;

max-height: 200px;
max-width: 150px;

margin-left: 100px; 
margin-right: 100px;
border:3px solid rgb(20, 11, 11);
  
}
<div class="multiple-items" id="suitei-slider"></div>
<input type="hidden" id="sendServ">

Answer №1

To ensure that your canvases are properly positioned within a container, it is essential to set them in position: absolute inside a container with position: relative. This way, the canvases remain contained within the container without overlapping. Although the containers themselves are not in position: absolute, their content may overlap, causing your canvases to overlay with the images.

Additionally, you may need to center your canvases by setting their dimensions (which can be hard coded for now) and fixing the x position of the circle.

I hope this information aligns with what you were seeking.

document.body.onload = addElement;

      function addElement() {
            
            // image path
            const imagePath = ['https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fen%2F8%2F84%2FAssociation_of_Gay_and_Lesbian_Psychiatrists_logo.jpg&f=1&nofb=1', 'https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fstatic01.nyt.com%2Fnewsgraphics%2F2016%2F07%2F14%2Fpluto-one-year%2Fassets%2Ficon-pluto.png&f=1&nofb=1', 'https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse4.mm.bing.net%2Fth%3Fid%3DOIP.oFxADNN67dYP-ke5xg7HbQHaHG%26pid%3DApi&f=1', 'https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fmedia.glassdoor.com%2Fsqll%2F1065746%2Felevation-church-squarelogo-1453223965790.png&f=1&nofb=1'];
            
            for (const image of imagePath) {
                  // get the item id of an image
                  var slice = image.slice(26, 34);
                  var id = image;
                  var hdnName = document.getElementById("sendServ"); 

                  const img = document.createElement("img");
                  img.src = image;
                  img.classList.add("new");
                  img.id = slice;

                  const cnvs = document.createElement("canvas");
                  cnvs.classList.add("suiteiCanvas");
                 
                 // cnvs.style.position = 'absolute';
                  cnvs.style.left = img.offsetLeft + "px";
                  cnvs.style.top = img.offsetTop + "px";
                  cnvs.style.display = 'none';
                  cnvs.width = 150;
                  cnvs.height = 150;

                  var ctx = cnvs.getContext("2d");
                  ctx.clearRect(0, 0, cnvs.width, cnvs.height);
                  ctx.beginPath();
                  ctx.arc(75, 75, 50, 0, 2 * Math.PI, false);
                  ctx.lineWidth = 15;
                  ctx.strokeStyle = '#FF0000';
                  ctx.stroke();

                  var div = document.createElement("div");
                  var div1 = document.createElement("div");
                  div.id = id;
                  div1.id = '1';
                  div.classList.add("image");


                  img.onclick = function draw() {
                        cnvs.style.display = '';
                        hdnName.value = img.id;
                  };

                  cnvs.onclick = function remove() {
                        cnvs.style.display = 'none';
                        hdnName.value = null;
                  };

                  document.getElementById('suitei-slider').appendChild(div);
               
                  document.getElementById(image).appendChild(img);
                  document.getElementById(image).appendChild(cnvs);
               
               
            }
      }
      
// slick slider
.image {
  position: relative; /* add this */
  user-select: none; /* and this maybe */
}

canvas.suiteiCanvas{
  height: auto; 
  width: auto;
  height: 150px;
  max-width: 150px;
  /*margin-left: 100px; 
  margin-right: 100px;*/
  border:3px solid rgb(20, 11, 11);
  position: absolute; /* add this */
}

#draw-btn {
  font-size: 14px;
  padding: 2px 16px 3px 16px;
  margin-bottom: 8px;
}

img.new { 
  height: auto; 
  width: auto;
  max-height: 200px;
  max-width: 150px;
  /*margin-left: 100px; 
  margin-right: 100px;*/
  border:3px solid rgb(20, 11, 11);
  
}
<div class="multiple-items" id="suitei-slider"></div>
<input type="hidden" id="sendServ">

Answer №2

For clarification, here is a cleaner version of the code with comments to explain each line. Your code seems a bit confusing; consider using functions more frequently for readability.

let index = 0;
const display = "table"; // or "grid" if horizontal
const x = 0;
const y = 0;
const images = {
  height: 50,
  width: 50,
  url: [
    'image_url_1',
    'image_url_2',
    'image_url_3',
    'image_url_4'
  ]
}

function createHTML() {
  console.log('E: Execute & R: Request & I: Informative');
  
  document.body.style.display = display;
  for (const image of images.url) {
    
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    canvas.id = 'option' + [index];
    canvas.height = images.height;
    canvas.width = images.width;
    canvas.style.padding = '10px';

    drawImages(canvas);

    canvas.addEventListener("click", optionClick, false);

    document.body.appendChild(canvas);
    index++;
  }
}

function drawImages(canvas) {
  
  const ctx = canvas.getContext('2d');
  const background = new Image();

  index = canvas.id.replace(/\D/g, '');

  background.src = images.url[index];
  
  background.onload = function() {
    ctx.drawImage(background, 0, 0, canvas.width, canvas.height);
  }
}

function drawX(canvas) {
  const ctx = canvas.getContext('2d');

  console.log('E: Placing X on canvas ' + canvas.id);

  ctx.beginPath();
  ctx.moveTo(0, 0);
  ctx.lineTo(images.width, images.height);
  ctx.moveTo(images.height, 0);
  ctx.lineTo(0, images.width);
  ctx.closePath();
  ctx.stroke();
}

function clear(canvas) {
  console.log('E: clearing canvas ' + canvas.id);

  canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);

  drawImages(canvas);
}

function optionClick(e) {
  log = true;
  const canvas = document.getElementsByTagName('canvas');
  for (const option of canvas) {
    if (log) console.log('I: User clicked at option ' + e.target.id + ':' + option.id);
    log = false;
    if (e.target.id === option.id) {
      console.log('R: Drawing request at canvas ' + option.id);
      drawX(option);
    } else {
      console.log('R: Clearing request at canvas ' + option.id);
      clear(option);
    }
  }
}

window.onload = createHTML;
css_styles_here
<body></body>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The functionality of displaying a loading image when the Upload button is clicked has encountered a glitch and

I am looking to add a feature that displays a loader when a user uploads a file by clicking on a button. The loader should be visible while the data is being processed in the background. To achieve this, I have included a div as shown below: <div id=" ...

How to retrieve information from a pre-populated <textarea> using Google Maps script in AngularJS

Is there a way to transfer data from a prefilled <textarea> that is populated by accessing the Google Maps API in a JavaScript script, into an AngularJS controller? $scope.Add=function(msg){ $log.log(msg) } <div ng-app=""> <div ng-contro ...

Simulate a new Date object in Deno for testing purposes

Has anyone successfully implemented something similar to jest.spyOn(global, 'Date').mockImplementation(() => now); in Deno? I've searched through the Deno documentation for mock functionality available at this link, as well as explored t ...

Several different factors

I need to develop a form that allows users to edit existing comments. The form will display a textarea containing the old comment text and a submit button. My goal is to send the newComment data via ajax to another script. However, I am facing an issue w ...

jQuery load fails to fill select dropdown

Upon page load, my code executes a call to mysql to populate a select element with data. This process works smoothly on the initial load or when the page is refreshed. However, I am encountering an issue when attempting to update or repopulate the select e ...

The concealed [hidden] attribute in Angular2 triggers the display of the element after a brief delay

I am currently utilizing the [hidden] attribute within my application to conceal certain elements based on a specific condition. The situation is such that I have two divs - one for displaying results and another for showing the text "No results". Both t ...

Clear the text in a textarea after submitting the form

I am facing an issue with a comment box (textarea) inside a dialog. After successfully saving the comment, I want to clear the content of the textarea and close the dialog box. Currently, the dialog box closes, but the content remains in the textarea. < ...

Tips for assigning a unique identifier to an HTML tag using JavaScript

When appending multiple items in JavaScript like this: data.context = $('<button class="btn btn-primary"/>').text('Upload') .appendTo('#fileTableId') .click(function () { ...

Embed the svg element within a specified class

I am seeking guidance on how to insert an SVG that I created into a CSS or SCSS class, so that only the class is assigned to the icon, similar to this example from W3Schools: <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> ...

eliminating list item from unordered list depending on the input of either first or last name

My objective is to refine a lengthy list as the user types in a search for a specific person by first or last name. The current code I have functions adequately, but encounters an issue when there is a space in the input field. My goal is to allow users to ...

I'm having trouble getting the activeStyle to work properly with a <NavLink>

I'm facing an issue with setting activeStyle for the NavLink component when the URL is on the map route. Currently, when I click on a NavLink, I can navigate to the correct route, but only <NavLink to='/' is being highlighted as active. ...

What is the best way to retrieve AJAX responses from JSON data that contains multiple sets of information

["12-Feb-2017","06-Feb-2017","5","45","40","Neha shishodia","USD","unit2","phase1","Change Request","Client Approval Awaited"]["07-Feb-2017","04-Feb-2017","6","54","48","Neha shishodia","USD","unit2","phase1","Change Request","Manager Approval Awaited"] T ...

Nested loops iterating over an array of objects

I am working with a JSON file that contains my data: { "EIC": { "id": "EIC", "text": "Want to do a quick word game?", "replies": ["Sure", "Later"] }, "YMB": { "id": "YMB", "text": "Okay, tomorrow. Cya!", "replies": ["bye Woeb ...

Adjusting the repeating-linear-gradient CSS background

My goal is to make adjustments to a specific CSS code, in this case it is the repeating-linear-gradient. Take a look at my current implementation: input[type="range"]::-moz-range-track { background: repeating-linear-gradient(to right, #ccc, # ...

Implementing a basic marker clustering feature in the Google Maps application

I'm currently experiencing issues with implementing marker clusterer functionality on my map. I am trying to use a custom icon for each marker and have individual info windows that are editable. I was able to achieve this, but now I am facing difficu ...

Ensuring safe access to a Vue.js single-page application

After following numerous Vue.js tutorials, I have encountered a dilemma. Imagine I am constructing a single-page application where a user can log in and access data through a RESTful API. The initial step involves sending login credentials (username and p ...

Ways to detach event listener in Vue Component

One of my Vue2 components has a custom eventListener that I added in the mounted lifecycle hook. I am now trying to figure out the correct way to remove this listener when the component is destroyed. <template> <div> ... </di ...

Issues with AngularJS and UI-grid: the gridOptions are being overlooked by the grid

Having trouble with ui-grid disabling grid menu and renaming columns? Check out this plnkr I made: https://plnkr.co/edit/EGhvBGOJCKPzfupjCROx?p=preview In the script.js, I want my columns to be named 'banana', 'chrom', and 'positi ...

Exploring the world of web development with JavaScript and the randomization magic

As per information from a Stack Overflow discussion, Math.random() in JavaScript seems to rely on the browser or operating system, indicating that there is no standard algorithm for generating uniform random variables in JavaScript. Another discussion thre ...

Transmit JSON information from one webpage and dynamically retrieve it from another page via AJAX while both pages are active

I am attempting to transfer JSON data from page1 when the submit button is clicked and then retrieve this data dynamically from page2 using AJAX in order to display it in the console. I am unsure of the correct syntax to accomplish this task. There was a s ...