Is it possible to conceal any spans that are in close proximity to the cursor when hovered over?

Currently, I am working on a project that involves multiple spans placed side by side, with each span containing a letter of the text. My aim is to create a functionality where hovering over one of these spans will not only hide that particular span but also others nearby.

This setup produces an image resembling the following:

@@@@@@@@@@@@@@  
@@@@@@@@@@@@@@  
@@@@@@@@@@@@@@  
@@@@@@@@@@@@@@

The objective here is to conceal all spans within a specific distance from the mouse pointer, as illustrated in this example:

https://i.sstatic.net/fkXze.png

In terms of HTML structure:

<span id="overlay-1">@</span>
<!-- ... -->
<span id="overlay-142">@</span>
<span id="overlay-143">@</span>

I have managed to hide individual spans by targeting their IDs upon mouseover and modifying the style property to display=none. However, my main challenge lies in hiding all spans located close to the mouse cursor. Do you have any suggestions or solutions for this issue?

Answer №1

I attempted to tackle this challenge using JavaScript. Below is the code I came up with:

function draw() {
    let content = "";
    for (let col = 0; col < 100; col++) {
        content += "<div>"
        for (let row = 0; row < 100; row++) {
            content += `<span onmouseout="hoverOff()" onmouseover="hoverOver(this)" id="overlay-${row}-${col}">@</span>`
        }
        content += "</div>"
    }
    document.getElementById('drawing').innerHTML += content
}

function hoverOver(element) {
    let id = element.id;
    let row = element.id.split('-')[1];
    let col = element.id.split('-')[2];
    
    for (let x = -2; x <= 2; x++) {
        for (let y = -1; y <= 1; y++) {
            const item = document.getElementById(`overlay-${row-x}-${col-y}`);
            item ? item.style.opacity = 0 : null;
        }
    }
    element.style.opacity = '0';
}

function hoverOff() {
    for (let i = 0; i < document.getElementsByTagName('span').length; i++) {
        document.getElementsByTagName('span')[i].style.opacity = 1;
    }
}
<body onload="draw()">
    <div id="drawing">
    </div>
</body>

Answer №2

To achieve this without relying on specific ids, an alternative method involves utilizing the Element.getBoundingClientRect() function to determine the size and location of the element being hovered over. Subsequently, the use of Document.elementFromPoint() within a loop allows for accessing elements in close proximity to the target:

const main = document.querySelector('main')
for (let i = 0; i < 800; i++) main.innerHTML += '<span>@</span>'
const spans = document.querySelectorAll('span')

const areaWidth = 50
const areaHeight = 50
const hidden = []

function getElements(currentSpan, color) {
  const { top, right, bottom, left, width, height } = currentSpan.getBoundingClientRect()

  for (let col = left - areaWidth / 2; col < right + areaWidth / 2; col += width || 14) {
    for (let row = top - areaHeight / 2; row < bottom + areaHeight / 2; row += height || 14) {
      const el = document.elementFromPoint(col, row)
      if (el?.tagName === 'SPAN') {
        el.style.color = color
        hidden.push(el)
      }
    }
  }
}

spans.forEach(span => {
  span.addEventListener('mouseover', () => getElements(span, 'transparent'))
  span.addEventListener('mouseout', () => {
    hidden.forEach(el => (el.style.color = ''))
    hidden.length = 0
  })
})
main {
  display: flex;
  flex-wrap: wrap;
  width: 640px;
  cursor: default;
}
<main></main>

Answer №3

If you're looking to hide adjacent characters upon clicking, one solution could be using CSS to overwrite those characters with a pseudo element.

This code snippet utilizes a monospace font and defines line height and letter spacing as CSS variables, allowing for easy customization.

function clicked(ev) {
  ev.target.classList.add('obscure');
}
const container = document.querySelector('.container');
for (let i = 0; i < 200; i++) {
  const span = document.createElement('span');
  span.innerHTML = '@';
  if (i % 10 == 0) {
    container.innerHTML += '<br>';
  }
  container.appendChild(span);
}
container.addEventListener('click', clicked);
.container {
  width: 50vw;
  height: auto;
  font-family: Courier, monospace;
  --line-height: 20px;
  --letter-spacing: 5px;
  line-height: var(--line-height);
  letter-spacing: var(--letter-spacing);
}

.container span {
  position: relative;
  margin: 0;
  padding: 0;
}

.obscure::before {
  content: '';
  width: calc(5ch + (6 * var(--letter-spacing)));
  height: calc(3 * var(--line-height));
  background-color: white;
  position: absolute;
  top: 0;
  transform: translate(calc(-50% + 0.5ch), calc(-50% + (1ch)));
  left: 0;
  z-index: 1;
  display: inline-block;
}
<body>
  <div class="container"></div>
</body>

Answer №4

It seems like you're looking to make the span disappear without affecting the layout. Using display:none won't achieve this, but visibility:hidden will do the trick.

Hiding the hovered element and its adjacent elements is straightforward. The real challenge lies in hiding elements above or below it.

To accomplish this, some calculations are necessary.

If an exact solution isn't required, you could try something like this:

  1. Determine the center positions of all spans and store them in an array to avoid recalculating each time.
  2. When a span is hovered over, identify all spans within a certain radius of that span's center point - whether above, below, left, or right.
  3. Create a new array of spans to hide based on the previous step.
  4. Review all currently hidden spans and unhide any that aren't included in the new array (set visibility:visible).
  5. Finally, loop through the new array and set visibility:hidden for all spans in that array.

Answer №5

Here is a unique and customizable approach:

// Customizing Variables
const ROW = 10; // Total number of rows available
const COL = 35; // Total number of items in each row
const RANGE = 2; // Number of items to be selected in each direction
const values = []; // Array to store ids of selected items

// Utility Function to add values to the array
const push = (value) => {
  if (value > 0 && value <= ROW * COL && !values.includes(value)) values.push(value);
};

// Adding items in the root div
const root = document.querySelector("#root");

for (let i = 0; i < ROW; i++) {
  root.innerHTML += `<div id="row-${i + 1}"></div>`;

  for (let j = 0; j < COL; j++) {
    document.querySelector(`#row-${i + 1}`).innerHTML += `<span id="item-${COL * i + (j + 1)}">@</span>`;
  }
}

// Adding class to the items based on the RANGE
root.addEventListener("mouseover", (e) => {
  values.length = 0;

  const id = e.target.id;
  if (!id.includes("item-")) return;

  const current = +id.replace("item-", "");
  push(current);

  for (let i = -RANGE; i < RANGE; i++) {
    push(current + i);

    for (let j = -RANGE; j <= RANGE; j++) {
      push(current + COL * i + j);
      push(current - COL * i + j);
    }
  }

  for (let i = 0; i < values.length; i++) {
    const item = document.querySelector(`#item-${values[i]}`);
    item.classList.add("selected");
  }
});

// Removing class from the items once the mouse is out as per the RANGE
root.addEventListener("mouseout", () => {
  for (let i = 0; i < values.length; i++) {
    const item = document.querySelector(`#item-${values[i]}`);
    item.classList.remove("selected");
  }
});
/* Styling purpose only */
body {
  background-color: #111;
  color: #fff;
}

#root [id*="item-"] {
  padding: 1px;
}

/* Styles for the selected item */
#root [id*="item-"].selected {
  /* color: transparent; */ /* You can uncomment this line for desired effect */
  color: #ffa600;
}
<div id="root"></div>

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

What is the best way to add data from an array to a DOM element in the same order it was retrieved from Firebase?

Utilizing Google Firebase Firestore for data storage and the Open Movie Database (OMD) in combination with Axios to retrieve movie information. I am currently developing a website that allows users to add movies to collections. On the collections page, al ...

Incorporate a line break into a document using JavaScript

Is there a way to make all the items inside document.get on new lines without using paragraph elements? I have tried br/ and \n, but they do not work as expected. They either cause issues with JavaScript execution or fail to create new lines. <scr ...

What's the best way to show floating point numbers in a concise format while also maintaining the ability to perform calculations within this Vue app?

I'm currently developing a compact calculator application using Vue 3 and implementing some custom CSS. For the most part, everything seems to be functioning correctly, except for when the results are long numbers that extend beyond the display limit ...

How can I ensure that my jQuery code only executes after the mobile CSS has been loaded

When it comes to loading my mobile-only CSS, I typically use a media query similar to: <link rel="stylesheet" type="text/css" media="only screen and (max-device-width: 480px)" href="/includes/css/mobile.css" /> However, in addition to these CSS mod ...

Ensuring the authenticity of user login credentials

I have a form in my HTML where the user needs to input their name and password. <html> <body> <form action="welcome.php" method="post"> Name: <input type="text" name="name"><br> Password: <input type="text" name="password ...

When the JavaScript string retrieved from the database is null, it will be displayed as an empty string

Currently, my Ajax setup involves querying a database on the server with SELECT someColumn FROM someTable. The returned value of someColumn is then updated on the client side by using $('#someElement').text(someColumn); Everything works perfectl ...

Retrieving the selected date from JqueryUI Datepicker after form submission

I am currently using an inline datepicker that fills in an input textbox. $("#left-calendar").datepicker({ altField: "#left-date-text" }); The left-date-text is located within a form, and upon submission with a submit button, it sends the data to a p ...

Ways to extract single JSON entities from a consolidated JSON structure

I am facing a challenge with parsing multiple JSON objects within a single large JSON object. Currently, the entire JSON object is being stored as one entity, but I need to parse and store them separately in MongoDB. Below is the code snippet I am using. ...

Are there any "Undefined" tabs hiding in your RMarkdown tabsets?

After knitting my RMarkdown document to an HTML file, I noticed that the tabs appeared as shown below: However, when I save and share the document with my audience, I encounter an issue where these tabs are labeled as "undefined". Just to clarify, this pr ...

What is the accurate way to write the ID selector for the select-option-selected in JQuery?

When it comes to extracting a value from a Select-Option using jQuery, the following syntax can be used. I have successfully retrieved data using this method. $( "#Vienna\\.rail0\\.track option:selected" ).text() However, there is an ...

When querying the model, the result may be undefined

I'm encountering an issue where I can't access the content of an array of documents in my model and it's returning undefined. Here is the model structure (Project.js): var mongoose = require('moongoose'); var Schema = mongo ...

Present location of current page

I utilize angularJS to create a web page with the utilization of ngView for a single page and multiview. Is there a way to display the current page's location, such as Home/abc/dcv? On this website https://docs.angularjs.org/guide/, the page location ...

Ways to identify when the scroll bar reaches the end of the modal dialog box

I have been working on a modal that should display an alert when the scrollbar reaches the bottom. Despite my efforts to research a solution, I am struggling to detect this specific event within the modal. The desired outcome is for an alert to pop up once ...

Experiencing pagination problems with Vue / Laravel framework

Trying to implement pagination for fetched data in a Vue project, but encountering an issue: New Question Error encountered during rendering: "TypeError: this.estates.filter is not a function" Am I overlooking something here? Pagination.vue ...

Could the issue be related to a bug in the combination of ng-repeat and ngInclude?

I've been experimenting with loading different templates in this manner: <div ng-class="{active:$first,in:$first,'tab-pane':true}" id="{{p.path}}_settings" ng-repeat="p in panes" ng-include="buildPath(p.path)"> </div> Here&apos ...

A beginner's guide to integrating ng-class into a directive template using AngularJS

I have been attempting to achieve something similar to the following: template: "<div ng-if=\"successData\" ng-class=\"{ 'bounceInDown': successData == true,bounceInDown: successData == false}\" style=\"border-radius ...

Ensure that background elements do not become the focus when using MUI backdrop

Currently, we are implementing screen dimming when a custom dialog is open using MUI backdrop. However, even though the screen is "grayed-out," users can still access the items with the keyboard. In the image below, you can see how I move from "show backd ...

Centered Fixed Upward Scrolling Div

Currently facing a challenge with my project involving a chat interface created in Angular. I am struggling with the CSS styling as the chat starts at the top and scrolls downward off-screen as the conversation progresses. Although I can scroll along with ...

Is there a way to raise an error in React Native and make it visible?

I am working on a functional component where I need to call a method from another .js file. The method in the external file intentionally throws an error for testing purposes, but I want to propagate this error up to the functional component's method. ...

Building an Angular module that allows for customizable properties: A step-by-step guide

I am in the process of developing an AngularJS module that will simplify interactions with my product's REST API. Since my product is installed on-premise, each user will need to provide their own URL to access the API. Therefore, it is essential that ...