Click 2 elements at the same time?

Drew Cordano :

I have a scenario where a user can choose 1 element or 2 elements to click
If the user choosed 2 elements he can choose 2 elements in a single click but only to its neighbour element
Ex:
If user click on Elem 1 container, container below will be active or clicked
Elem 1 and Elem 2
If user click on Elem 3 container, container below will be active or clicked
Elem 2 and Elem 3

Moreover if user clicked on Elem 2 it will depend on the nearest area where the user clicked(the Y axis) if it will be partnered with Elem 1 or Elem 3

But NOT Elem 1 to 3 because there is a gap between them(the Elem 2) and as I've mention only the neighbour container.

I am using ReactJS

enter image description here

<div class="myClass">
  Elem 1
</div>

<div class="myClass">
  Elem 2
</div>

<div class="myClass">
  Elem 3
</div>
iamcastelli :

Edit 1

Based on the OP's subsequent comments, I realized they also wanted the second selected item to depend on how close the item is to the click position. I made some updates.

See updated React Code Sandbox here


App.jsx

import React, { useState } from "react";
import "./styles.css";

const ElementsList = () => {
  // 1. List of Items, they could be anything
  const items = ["Elem 1", "Elem 2", "Elem 3", "Element 4", "Element 5"];

  // 2. Track the selected items in state
  const [selectedItems, setSelectedItems] = useState([]);

  const handleClick = (e, index) => {
    // 7. Extract the click position and element height from the event target.
    const nextItems = getNextSelections({
      currentIndex: index,
      totalItems: items.length,
      elementHeight: e.currentTarget.getBoundingClientRect().height,
      distanceFromTop: e.clientY - e.currentTarget.getBoundingClientRect().top
    });

    // 4. Do whatever you want with the selected items :), then update state
    setSelectedItems(nextItems);
  };

  return (
    <div className="List">
      {items.map((value, index) => (
        <div
          key={value}
          className={`myClass ${
            // 5. Conditionally set selected class if index is present in selected Items array
            selectedItems.includes(index) ? "selected" : ""
          }`}
          // 6. Capture the click event and the index of the selected item
          onClick={e => handleClick(e, index)}
        >
          {value}
        </div>
      ))}
    </div>
  );
};

export default function App() {
  return (
    <div className="App">
      <h1>2 Items Selector</h1>
      <ElementsList />
    </div>
  );
}

getNextSelections helper


// Helper to get Select items based on mouse position
const getNextSelections = ({
  currentIndex, // Index of the clicked Item
  totalItems, // Total number of items in the list
  elementHeight, // Height of the bounding rectangle of the element
  distanceFromTop // Distance of Mouse click postion from top of boudning rectangle of the element
}) => {
  // A. Return first and second item if first item is clicked, exit early
  if (currentIndex <= 0) return [0, 1];

  // B. Return last and second last if last item is clicked and exit early
  if (currentIndex === totalItems - 1) return [currentIndex - 1, currentIndex];

  // C. If clicked in top half of the element, return previous and current item
  if (distanceFromTop < elementHeight / 2) {
    console.log("Cicked Next to the Top of Element");
    return [currentIndex - 1, currentIndex];
  }

  // D. Otherwise return current and next item indicies
  return [currentIndex, currentIndex + 1];
};

styles.css

.App {
  font-family: sans-serif;
  text-align: center;
}

.List {
  width: 80%;
  margin: 0 auto;
  text-align: center;
}

.myClass {
  padding: 1rem;
  border: solid 4px black;
  border-bottom: none;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.myClass.selected {
  background: rgb(236, 174, 174);
  transition: background 1s;
}
.myClass:last-child {
  border: solid 4px black;
}


I have added a helper to conditionally check the click position from the top of the selected element's bounding rectangle. Followed these assumptions.

  1. If the first item is clicked, just choose the first and second items.[A]
  2. Choose the last and second last item if the last one is clicked. [B]
  3. For elements in the middle of the list, choose the previous item as the second selection if the click happens in the top half of the clicked item's bounding rectangle [C], otherwise choose the previous item. [D]

Code Sandbox here

Edit 2

In your comments you say the list has rows and columns :( You can extend the helper to account for the horizontal proximity using getBoundingClientRect().left and width, and use the same approach to select the index of items to the side closest to the click. Will update this when I get the time :)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=19930&siteId=1