Encircling a particular group of cells with a border

I have completed the component with a table layout.

My current challenge is figuring out how to surround a range of selected cells with a border, similar to the first cell in the group shown below:

https://i.stack.imgur.com/5Euht.png

I attempted using different classes for each cell's border style, but it seems impossible as I cannot predict which cells the user will select or determine the size of the cell group.

Thank you in advance and please excuse any language errors.

Answer №1

Unfortunately, the question I had to tackle this week didn't have a straightforward answer, aside from suggesting the use of external libraries. Here is my unique approach to solving the problem.

In this example, I am utilizing the Marked class to highlight selected cells and the dataset attribute to indicate which cells define outer boundaries.

;window.onload = (event) => {
  // Setting up mousedown event  
  document.querySelector('table').addEventListener('mousedown',_onMouseDownTable, false)
};

/***
* Handling MouseDown event for the table
*/
function _onMouseDownTable(event){
  // Checking if 'td' element...
  if(
    event.target &&
    event.target.tagName.toLowerCase() === 'td'
  ){
    const tObject = {Down: event.target};

    // Adding event listener for marking cells
    this.onmousemove = ((object, event) => {
      if(
        event.target &&
        event.target.tagName.toLowerCase() === 'td'
      ){
        object.Move = event.target
      }
      else{
        delete object.Move
      };

      _markCells(object.Down, object.Move)
    }).bind(null, tObject);

    // Event listener for finishing cell marking
    this.onmouseleave = this.onmouseup = ((object, event) => {
      this.onmouseleave = this.onmousemove = this.onmouseup = null;
    }).bind(null, tObject)
  }
};

/***
* Marks cells between cell a and cell b
*/
function _markCells(a, b){
  if(a && b){
    // Finding parent table of cell a (usually same as b)
    const tTable = a.closest('table');

    // Clearing existing marks and border data
    tTable.querySelectorAll('td.Marked, td[data-bounds-left], td[data-bounds-right], td[data-bounds-top], td[data-bounds-bottom]').forEach((td) => {
      td.classList.remove('Marked');

      delete td.dataset.boundsLeft;
      delete td.dataset.boundsRight;
      delete td.dataset.boundsTop;
      delete td.dataset.boundsBottom
    });

    // Identifying the smallest (top/left) and largest coordinates
    const
      tMaxColumn = Math.max(Number(a.dataset.columnIndex), Number(b.dataset.columnIndex)),
      tMaxRow = Math.max(Number(a.dataset.rowIndex), Number(b.dataset.rowIndex)),
      tMinColumn = Math.min(Number(a.dataset.columnIndex), Number(b.dataset.columnIndex)),
      tMinRow = Math.min(Number(a.dataset.rowIndex), Number(b.dataset.rowIndex));

    // Marking all cells between Min and Max values
    for(let row = tMinRow; row <= tMaxRow; row++){
      for(let column = tMinColumn; column <= tMaxColumn; column++){
        const tCell = tTable.querySelector(`td[data-row-index='${row}'][data-column-index='${column}']`);
        if(tCell){
          // Marking as left boundary if applicable
          if(column === tMinColumn){
            tCell.dataset.boundsLeft = true
          };

          // Marking as right boundary if applicable
          if(column === tMaxColumn){
            tCell.dataset.boundsRight = true
          };

          // Marking as top boundary if applicable
          if(row === tMinRow){
            tCell.dataset.boundsTop = true
          };

          // Marking as bottom boundary if applicable
          if(row === tMaxRow){
            tCell.dataset.boundsBottom = true
          };

          // Setting cell as marked
          tCell.classList.add('Marked')
        }
      }
    }
  }
};
td{
  border: 2px solid #000;
  background-color: grey;
  height: 25px;
  width: 200px;
}

td.Marked{
  background-color: #1e90ff
}

td.Marked[data-bounds-left]{
    border-left-color: red
}

td.Marked[data-bounds-right]{
    border-right-color: red
}

td.Marked[data-bounds-top]{
    border-top-color: red
}

td.Marked[data-bounds-bottom]{
    border-bottom-color: red
}
<table>
  <tbody>
    <tr>
      <td data-column-index="0" data-row-index="0"></td>
      <td data-column-index="1" data-row-index="0"></td>
      <td data-column-index="2" data-row-index="0"></td>
      <td data-column-index="3" data-row-index="0"></td>
      <td data-column-index="4" data-row-index="0"></td>
    </tr>
    <tr>
      <td data-column-index="0" data-row-index="1"></td>
      <td data-column-index="1" data-row-index="1"></td>
      <td data-column-index="2" data-row-index="1"></td>
      <td data-column-index="3" data-row-index="1"></td>
      <td data-column-index="4" data-row-index="1"></td>
    </tr>
    <tr>
      <td data-column-index="0" data-row-index="2"></td>
      <td data-column-index="1" data-row-index="2"></td>
      <td data-column-index="2" data-row-index="2"></td>
      <td data-column-index="3" data-row-index="2"></td>
      <td data-column-index="4" data-row-index="2"></td>
    </tr>
    <tr>
      <td data-column-index="0" data-row-index="3"></td>
      <td data-column-index="1" data-row-index="3"></td>
      <td data-column-index="2" data-row-index="3"></td>
      <td data-column-index="3" data-row-index="3"></td>
      <td data-column-index="4" data-row-index="3"></td>
    </tr>
    <tr>
      <td data-column-index="0" data-row-index="4"></td>
      <td data-column-index="1" data-row-index="4"></td>
      <td data-column-index="2" data-row-index="4"></td>
      <td data-column-index="3" data-row-index="4"></td>
      <td data-column-index="4" data-row-index="4"></td>
    </tr>
  </tbody>
</table>

Please note that this solution is only a preliminary draft and may require further refinement based on specific implementation needs.

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

Transform a Django/Python dictionary into a JavaScript dictionary using JSON

I need to convert a Python dictionary into a JavaScript dictionary. From what I understand, I have to first convert the Python dict into JSON format and then transform it into a JavaScript Object. view.py jsonheaderdict = json.dumps(headerdict) {{jsonhe ...

Create a dynamic layout with two navigational sub-menu blocks positioned side by side

When I hover over a navigation menu item, it brings up 6 sub menu items. I want these sub-items to appear in two blocks of 3 that are adjacent to each other. I tried using display: flex on the parent element .menu-item-1, but it doesn't seem to be wo ...

Running Handlebars using NodeJS can sometimes result in a "Cannot find module './parser'" error

After successfully creating and implementing a Handlebars template in the Browser, my next goal is to utilize the Handlebars precompiler, which requires a NodeJS module. I have already downloaded Handlebars for NodeJS along with all dependencies locally (n ...

Unable to retrieve JSON element using Fetch

I'm attempting to retrieve a JSON file and exhibit its components within a div. Here is the JSON data I have: [ { "0":{ "host_id":"129230780", "host_names":"STK Homes", ...

Discovering the Javascript Code Executing on a <span> element with the Help of Chrome Inspector or Firebug

I have encountered a situation where a website is dynamically generating information into <span></span> tags using jQuery. The span has a class of "Price" and an id corresponding to a Product Code, with the data being pulled from a JSON data sh ...

Using an imported material icon as a background in JSS styling

I have implemented a draggable dialog component in React-mui with a resizable box feature. const styles = theme => ({ resizable: { position: "relative", "& .react-resizable-handle": { position: "absolute" ...

Utilize jQuery, Flash, or HTML5 to upload an image

Does anyone know of an upload tool or plugin that has a similar look and functionality to the one used on Codecanyon's website? I tried Uploadify, but it doesn't work on all browsers. I need something that is compatible with all browsers, whether ...

Having difficulty retrieving the selected value in JSPDF

I am attempting to convert my HTML page into a PDF format by utilizing the following code: domtoimage.toPng(document.getElementById('PrintForm')) .then(function (blob) { var pdf = new jsPDF('p', &apo ...

When altering the color of a mesh in Three.js, only a single face is impacted by the modification

I have a GLB model with multiple parts and hierarchy. My goal is to highlight a specific part of the assembly on mouseover. The code snippet I am using for this functionality is as follows: raycaster.setFromCamera( pointer, camera ); ...

unable to use 'await' keyword to delay the code execution until a function finishes

I'm encountering an issue where I need to wait for the result of a local function before proceeding further. Here is the code for the local function: var Messagehome = (req, res) => { user.find().exec(async (err, user) => { if (err) ret ...

Steps for implementing a Toggle Navigation Bar in CSS

I'm looking to implement a show/hide navigation menu similar to the one showcased in this inspiration source: Code Snippet (HTML) <div id="menus"> <nav id="nav"> <ul> <li><a href="#">HOME</a></li> <li& ...

How to make Angular resolver and component share an injected service?

In my products list component, I have a table displaying various products. Since there is a considerable amount of data, I implemented a resolver to prevent the user from being directed to the page until all the data is loaded. The resolver currently utili ...

Unresponsive HTML button

I'm currently developing an interactive text-based game that relies on button functionality to change text content. Everything was functioning perfectly until just a few moments ago, but now it has inexplicably stopped working. Here is the section of ...

Issue with the selected toggle menu

Whenever I click on a menu item's main div, its color changes. If I click again, the color remains the same. But now, I want the toggle menu to change its color when clicked, and then revert back to the color of the other parent divs when clicked agai ...

Avoid repeating media queries in MUI JSS by combining them efficiently

Is there a more efficient way to apply the same set of CSS styles to multiple media query rules without repetition? Currently, the only workaround seems to be: [theme.breakpoints.up('xl')]: { color: 'red', backgroundColor: 'gre ...

Running a Mongoimport command within a JavaScript/Node.js script

Is there a node.js/javascript library available that allows for the use of mongoimport within code? From what I understand, mongoimport is similar to an .exe file that needs to be executed before being able to utilize its text input environment. Is it fe ...

Avoid re-rendering the page in Nuxt when adjusting dynamic parameters

My page has two dynamic parameters that trigger the fetch method to run again when the URL params are changed. I want to avoid this behavior. Fetch Method: async fetch() { await this.getFlightResult(); } Get Result Method: async getResult() { th ...

Navigating the loading of information with fetch and React Hooks

As a newcomer to React and still learning JavaScript, I am facing a challenge with handling useEffect alongside an asynchronous function. My goal is to fetch data from an API and render a quote in the paragraph with id of text, along with the author's ...

Issue with Font Requests in Browsers when Using Angular 10 and SCSS with @font-face

I have a project built with Angular 10 that utilizes SCSS for styling. In my _typography.scss file, I have defined some @font-face rules pointing to the font files located in the assets/fonts directory. However, when I run the application, the browser does ...

To ensure that quotes are correctly handled in a string being passed to a JavaScript function within an `onclick`

I am facing an issue with a cycle in a jspx file that I have. The cycle looks like this: <c:forEach var="var" items="${dataFile.list.rows}"> <li> <div> <a href="#" onClick="myFunct('${var.url}','escape(${var ...