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

When the onload event is triggered, the jscript function called var data is loaded, without any interruption in

I encountered an issue while trying to preview an image from a BBCode decoder. The code works fine, but I need the image to be inside an <a> href link, so that people can click on it and get the image source. Additionally, I want to display a message ...

What is the best way to display two tables side by side in a Vue component?

I am working on a vue application with a photo collection feature. My goal is to display the photos in two tables per row, iterating through the entire collection. Here's an example of what I'm aiming for: <row> &l ...

Text within the footer section

When displaying the name of a subcategory, I want it in one line. However, if the subcategory name contains two words, it should be displayed in two lines. https://i.stack.imgur.com/CcDeL.png Code: .Footer { width: 100%; display ...

Tips for resolving the 'node-gyp rebuild' problem on Windows 10

While attempting to incorporate a node NPM dependency into my project, I encountered an issue with node-gyp rebuild, which I have already reported. I am aware of a potential solution from this Stack Overflow post, but unfortunately it is not effective for ...

What is the best practice for importing React components?

In my experience with React, I've noticed two different ways of importing and extending components. The first way that I typically use is shown below. import React from 'react'; class SomeClass extends React.Component { //Some code } ...

A helpful tip for creating line breaks within a Vue JS v-for loop using CSS

I am looking to arrange the names in alphabetical order when a list item is clicked. My tools of choice are Vue.js and Flex Grid. The list item I am working with is called ListAll, When clicking on ListAll, I want to display all the records grouped by na ...

"Encountering a net::ERR_UNKNOWN_URL_SCHEME error message when making an Ajax post request

I'm encountering an issue while attempting to make a post call using Ajax from my frontend to my Express server. The error message I'm getting is net::ERR_UNKNOWN_URL_SCHEME. Here's the code snippet for the Ajax request: function sendStep ...

Causes of the error message 'TypeError: res.render is not a function'

I have set up an express application with the following code: var express = require('express'); var router = express.Router(); var passport = require('passport'); var User = require('../models/user'); var request = require(&a ...

Encountering a classnotfound exception with JSP JDBC SERVLET, but all code appears to be

index.jsp <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> < ...

Ways to remove a dynamic field with jquery

I have developed a script that allows me to add dynamic fields and delete them as needed. However, I am facing an issue where I cannot delete the first element with the "el" class in my script because it removes all elements within the "input_fields_cont ...

Ensure that the navigation bar remains consistent when switching between pages

My issue lies within the React components I am working with. Essentially, my goal is to create a Single Page Application (SPA) using ReactJS. While setting up authentication using auth0-js, I also established some routes for navigation. The layout is stru ...

The placeholder text is not displaying with bullets in Internet Explorer. However, it is functioning correctly in Chrome

I need assistance displaying the placeholder text in IE8 as shown below: "Any relevant reference numbers, such as Direct Debits: - Name of the Branch (if applicable) - What was the original problem - Date the problem occurred " While it appears correct ...

Some elements in the DOM appear to not be rendering even though they are present in the HTML source code

As a newcomer to web development, I have stumbled upon a perplexing issue. In my usage of d3.js (specifically the script found here), I have been attempting to incorporate additional features. I modified my JavaScript code to include a simple <p> ele ...

help a figure leap within the confines of the artwork

Take a look at my jsfiddle here: http://jsfiddle.net/2tLCk/4/ When you press the up button, Mario jumps high into the air and then comes back down. However, if you press it again, he doesn't jump. How can I fix this issue so that when the up button i ...

What causes <input> elements to vertically center when using the same technique for centering <span> elements? (The line-height of <input> does not match its parent's height)

Important: The height of <div> is set to 50px, and the line-height of <span> is also 50px When 'line-height' is not applied to the <span>, all elements align at the top of the parent. However, when 'line-height: 50px&apo ...

Utilize AngularJS to Capitalize the First Letter and the Letter Following a Dot (.)

I am seeking a solution to capitalize the first letter in a given string, like so: sumo => Sumo Additionally, I need to capitalize strings in the following format: Dr.ravi kumar => Dr.Ravi kumar Although I have implemented an Angular filter that ...

Problem with Clerk's authentication() functionality

Currently facing an issue with the Clerk auth() helper (auth() documentation) while working with react and next 13 (app router). When trying to access both userId and user from auth(), const { userId, user } = auth();, it seems that userId contains a val ...

Issues with method invocation in jQuery's .ajax requestI am having

After reading this Stack Overflow post, I now understand how to retrieve a return value from an AJAX call: function GetIsDataReady(input) { $.ajax({ url: "http://www.blah.com/services/TestsService.svc/IsDataReady", ...

Having trouble in React.js when trying to run `npm start` with an

Upon initially building a todo app in react.js by using the command: npx create-react-app app_name When I proceeded to run the command npm start, it resulted in displaying errors: In further investigation, I discovered a log file with various lines that ...

The plugin "react" encountered a conflict while trying to sync with both the "package.json" and the "BaseConfig" files

Whenever I open Terminal in my react folder and try to start the react app using npm start, I always end up encountering an error on the browser. The error message states that the "react" plugin is conflicting between two paths: "package.json » eslint ...