Modify the color of a designated section of an image with a click of the mouse

As a novice following a tutorial, I am learning how to modify the color of a specific area within an image using various color options.

I can successfully change one area, but I am struggling with implementing changes for other areas.

My goal is to click on the desired region, have its border highlighted via CSS, and then alter the color using the available options.

What would be the most effective approach to achieve this? Would it be appropriate to utilize a switch statement along with onclick to select the particular image area?

const overlay = document.getElementById("product-a");
var el = document.getElementsByClassName("color");
for (var i = 0; i < el.length; i++) {
  el[i].onclick = changeColor;
}

function changeColor(e) {
  let hex = e.target.getAttribute("data-hex");
  overlay.style.fill = hex;
}
body,
html {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
}
#container {
  height: 200px;
  width: 200px;

}

#product-svg {
  position: relative;
  z-index: 2;
  background-size: 100%;
  background-repeat: no-repeat;
  background-position: 50%;
  mix-blend-mode: multiply;
}

path {
  fill: #CCCCCC;
}


#background-image {
  position: absolute;
  top: 0;
  left: 0;
  height: 200px;
  width: 200px;
  height: auto;
  z-index: 1;
}

.colors {
  display: flex;
  position: fixed;
  bottom: 2em;
  right: 2em;
  z-index: 3;
}

.color {
  height: 36px;
  width: 36px;
  margin-left: 0.5em;
  border-radius: 18px;
  box-shadow: 0px 4px 10px rgba(0,0,0,0.3);
  border: 2px solid #aaa;
  cursor: pointer;
}
<div id="container">

    <svg id="product-svg" viewBox="0 0 744 1074">
      <path id="product-a" d="M51 207.5L51 348L686 348L686 67L51 67L51 207.5Z" />
      <path id="product-b" d="M51 544.5L51 685L686 685L686 404L51 404L51 544.5Z" />
      <path id="product-c" d="M51 883.5L51 1024L686 1024L686 743L51 743L51 883.5Z" />
    </svg>
    <img id="background-image" src="boxes.jpg" alt="">
  </div>

  <div class="colors">
    <div class="color" style="background-color: #ff0000" data-hex="#ff0000"></div>
    <div class="color" style="background-color: #ffff33" data-hex="#ffff33"></div>
    <div class="color" style="background-color: #3399ff" data-hex="#3399ff"></div>
  </div>

Answer №1

Consider updating the overlay variable to be triggered by the onclick event of the product box instead of directly assigning it to #product-a.

let overlay;
document.querySelectorAll('#product-a, #product-b, #product-c').forEach(function(item) {
  item.onclick = selectProduct;
})

function selectProduct(e) {
  if (overlay) overlay.classList.remove('highlight')
  overlay = e.target
  overlay.classList.add('highlight')
}

var colors = document.getElementsByClassName("color");
for (var i = 0; i < colors.length; i++) {
  colors[i].onclick = changeColor;
}

function changeColor(e) {
  let hexValue = e.target.getAttribute("data-hex");
  if (overlay) overlay.style.fill = hexValue;
}
body,
html {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
}

#container {
  height: 200px;
  width: 200px;
}

#product-svg {
  position: relative;
  z-index: 2;
  background-size: 100%;
  background-repeat: no-repeat;
  background-position: 50%;
  mix-blend-mode: multiply;
}

path {
  fill: #CCCCCC;
}

#background-image {
  position: absolute;
  top: 0;
  left: 0;
  height: 200px;
  width: 200px;
  height: auto;
  z-index: 1;
}

.colors {
  display: flex;
  position: fixed;
  bottom: 2em;
  right: 2em;
  z-index: 3;
}

.color {
  height: 36px;
  width: 36px;
  margin-left: 0.5em;
  border-radius: 18px;
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.3);
  border: 2px solid #aaa;
  cursor: pointer;
}

.highlight {
  stroke-width: 10px;
  stroke: #000;
}
<div id="container">

  <svg id="product-svg" viewBox="0 0 744 1074">
      <path id="product-a" d="M51 207.5L51 348L686 348L686 67L51 67L51 207.5Z" />
      <path id="product-b" d="M51 544.5L51 685L686 685L686 404L51 404L51 544.5Z" />
      <path id="product-c" d="M51 883.5L51 1024L686 1024L686 743L51 743L51 883.5Z" />
    </svg>
  <img id="background-image" src="boxes.jpg" alt="">
</div>

<div class="colors">
  <div class="color" style="background-color: #ff0000" data-hex="#ff0000"></div>
  <div class="color" style="background-color: #ffff33" data-hex="#ffff33"></div>
  <div class="color" style="background-color: #3399ff" data-hex="#3399ff"></div>
</div>

Answer №2

One approach to consider is implementing a "select" feature that triggers upon clicking on specific sections. The feature could then visually distinguish the selected area by changing its border color, while also storing the area's identification in a variable.

Subsequently, another function can be set up to execute upon selecting a color swatch. This function would retrieve the stored area ID and target the corresponding HTML element accordingly.

Answer №3

It's a good idea to use a specific class to designate the selected item and then update that class upon clicking.

const elements = document.querySelectorAll(".color");
elements.forEach((el) => {
  el.addEventListener("click", changeColor);
});

function changeColor(e) {
  let hex = e.target.getAttribute("data-hex");
  document.querySelector('.product.selected').style.fill = hex;
}

document.querySelectorAll('.product').forEach((el) => {
  el.addEventListener('click', (e) => {
    document.querySelectorAll('.product').forEach((el) => {
      el.classList.remove('selected')
    });
    e.currentTarget.classList.add('selected');
  });
});
body,
html {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
}

#container {
  height: 200px;
  width: 200px;
}

#product-svg {
  position: relative;
  z-index: 2;
  background-size: 100%;
  background-repeat: no-repeat;
  background-position: 50%;
  mix-blend-mode: multiply;
}

path {
  fill: #CCCCCC;
}

#background-image {
  position: absolute;
  top: 0;
  left: 0;
  height: 200px;
  width: 200px;
  height: auto;
  z-index: 1;
}

.colors {
  display: flex;
  position: fixed;
  bottom: 2em;
  right: 2em;
  z-index: 3;
}

.color {
  height: 36px;
  width: 36px;
  margin-left: 0.5em;
  border-radius: 18px;
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.3);
  border: 2px solid #aaa;
  cursor: pointer;
}
<div id="container">

  <svg id="product-svg" viewBox="0 0 744 1074">
      <path class="product selected" id="product-a" d="M51 207.5L51 348L686 348L686 67L51 67L51 207.5Z" />
      <path class="product" id="product-b" d="M51 544.5L51 685L686 685L686 404L51 404L51 544.5Z" />
      <path class="product" id="product-c" d="M51 883.5L51 1024L686 1024L686 743L51 743L51 883.5Z" />
    </svg>
  <img id="background-image" src="boxes.jpg" alt="">
</div>

<div class="colors">
  <div class="color" style="background-color: #ff0000" data-hex="#ff0000"></div>
  <div class="color" style="background-color: #ffff33" data-hex="#ffff33"></div>
  <div class="color" style="background-color: #3399ff" data-hex="#3399ff"></div>
</div>

Answer №4

Utilizing the querySelectorAll function allows you to target all instances of <path> elements. You can then loop through these elements to attach an onclick event that adds a temporary class to the clicked overlay and changes its fill color.

const overlays = document.querySelectorAll("#product-svg path"); //Select all paths
var el = document.getElementsByClassName("color");
for (var i = 0; i < el.length; i++) {
  el[i].onclick = changeColor;
}

overlays.forEach(overlay => { //Iterate over all overlays
  overlay.onclick = () => {
    let id = this.id; // Get the id of clicked overlay
    overlays.forEach(overlay => {
      if (overlay.id != id) {
        overlay.classList.remove("active") //Remove the active class from other overlays
      }
    });
    overlay.classList.add("active") //Add active class to clicked overlay
  };
})

function changeColor(e) {
  let hex = e.target.getAttribute("data-hex");
  document.querySelector(".active").style.fill = hex; //Change the fill color for element with active class
}
body,
html {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
}

#container {
  height: 200px;
  width: 200px;
}

#product-svg {
  position: relative;
  z-index: 2;
  background-size: 100%;
  background-repeat: no-repeat;
  background-position: 50%;
  mix-blend-mode: multiply;
}

path {
  fill: #CCCCCC;
}

#background-image {
  position: absolute;
  top: 0;
  left: 0;
  height: 200px;
  width: 200px;
  height: auto;
  z-index: 1;
}

.colors {
  display: flex;
  position: fixed;
  bottom: 2em;
  right: 2em;
  z-index: 3;
}

.color {
  height: 36px;
  width: 36px;
  margin-left: 0.5em;
  border-radius: 18px;
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.3);
  border: 2px solid #aaa;
  cursor: pointer;
}
<div id="container">

  <svg id="product-svg" viewBox="0 0 744 1074">
      <path class="active" id="product-a" d="M51 207.5L51 348L686 348L686 67L51 67L51 207.5Z" />
      <path id="product-b" d="M51 544.5L51 685L686 685L686 404L51 404L51 544.5Z" />
      <path id="product-c" d="M51 883.5L51 1024L686 1024L686 743L51 743L51 883.5Z" />
    </svg>
  <img id="background-image" src="boxes.jpg" alt="">
</div>

<div class="colors">
  <div class="color" style="background-color: #ff0000" data-hex="#ff0000"></div>
  <div class="color" style="background-color: #ffff33" data-hex="#ffff33"></div>
  <div class="color" style="background-color: #3399ff" data-hex="#3399ff"></div>
</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

Unveiling the search bar as it expands horizontally from the center, causing the submit button to slide to adjust

Wishes and Aspirations My goal is to design an .input-group with one input[type=text] and one button[type=button]. Initially, the text box should be hidden, leaving only the button visible at the center of the page. Upon activation, the text box should ...

A new module is unable to load Angular Material

Recently, I developed an Angular material module similar to a core module. import { NgModule} from '@angular import {MatCheckboxModule} from '@angular/material/checkbox'; @NgModule({ imports: [ MatCheckboxModule ], exports: [ ...

What is the best method to extract and manipulate data from a JSON file in an AngularJS application?

personManagerInstance.getString("firstname",'common','en') I am currently passing a direct string in the UI which is affecting it. What I actually need is to read the data from a JSON file and return it as a string. personManagerInstan ...

Should data be sent via ajax to the server before reloading the page to view the results, or is it more efficient to update the DOM using JavaScript?

Hello there, I am working on a Django (3.1) site that has some interactive features where users can add, edit, and delete comments using html/javascript code. Currently, when a user performs one of these actions, the script sends the data to the server vi ...

Eliminate styling that is specific to certain browsers

Recent browser updates have introduced new styling and functionality to input[type=number], including up and down buttons. In Chrome, I was able to eliminate this added styling by accessing the shadow DOM and identifying the specific element. However, de ...

What is the process for creating a server-side API call?

I've designed a front-end application that uses an API to retrieve data. The problem I'm facing is that in order to access the API, I need to use an API Key. If I include the API key in the client-side code, it will be visible to users. How can I ...

What is the best way to trigger the onclick event before onblur event?

I have two elements - an anchor with an onclick function and an input with an onfocus event. The anchor is toggled by the input button; meaning, when the button is in focus, the anchor is displayed, and when it loses focus, the anchor is hidden. I'm l ...

Utilizing Ajax to redirect users

Just finished creating a test Ajax call function in my script to add a basic layer of protection to my website. Here is the code: function testPHP() { $.ajax({ type: 'post', url: 'file.php', success: function() { al ...

Map checkboxes aren't updating after an array update following a refactor to react hooks

I recently transformed a class component into a function component using hooks. However, I am facing an issue where the checkboxes within a specific mapping are not updating with the checked value. The onChange handler is firing and updating the array corr ...

Is it possible for Express in Node.js to handle multiple static folders at once?

Currently, I am working on a project that involves a user uploaded collection of styles, scripts, and images as well as my app's own collection of these resources. They are stored in separate directories on my server. I am wondering if there is a way ...

Creating Styles in Material-UI using makeStyles: Tips for Styling by Element Name

I am currently facing a challenge of adding a rule for all <p> tags within the current component. Despite searching through various sources such as material-ui documentation and Stack Overflow, I have been unable to find any information on how to add ...

Guide to appending the chosen item from a search bar to a fresh array using vue3 js

Does anyone know how to resolve the issue I'm facing with adding selected items from a dropdown list to a new array and displaying them on the page? Currently, I have added an onblur event to the input field to hide the dropdown when clicked outside, ...

How to perfectly align responsive email on iPhone 6

My email design appears aligned to the left on iPhone 6 even though I have used align="center" on the tables and TD's. In my media queries, I have specified a width of 320px with the main table set to width="100%". @media only screen and (max-device- ...

When the ENTER button is pressed in the BUTTON, the keyup event is triggered in the

I am facing an issue with this particular scenario: 1 input 1 button Using jQuery, I have the following bindings: input.keyup = intercept the ENTER press and display an alert message button.click = simply focus on the input field To replicate the probl ...

The D3js visualization is failing to display properly for the user, with the D3 source code residing on the server

I have encountered an issue after transferring my D3js chart generation system from a development server with no problems to a live Windows 2008 r2 server. On the live server, only the background SVG element is displayed and none of the other elements like ...

Are Stacked DIVs with Variable Height Top DIV Compatible with CSS?

I am currently experimenting with stacking two boxes on my mobile web application view using HTML/CSS. I prefer not to utilize JavaScript or hardcode values in this basic design. Specifics: The top box must have a dynamic height, with contents that ar ...

Stopping a setInterval countdown timer in a React component

Recently, I've been working on creating a pomodoro timer that includes a pause option. The timer features both an analogue clock and a digital timer. I have encountered a challenge with the digital timer - while I am able to pause it by clearing the i ...

What is the process for binding attributes using v-bind with a one-time binding?

Currently, I am utilizing the vue-i18n library for localization purposes. An issue I have encountered is when attempting to translate input placeholders using the following syntax: <input type="text" v-model="someValue" :placeholder="$t('translati ...

The best way to dynamically render HTML based on screen size using server-side rendering in Vue/Nuxt

Imagine having specific markup that should only be displayed on desktop using v-if. If the user is on mobile, a different content should be shown using v-else. The vue-mq package allows for setting a default breakpoint to use for server-side rendering. ...

A dialog box resembling a tooltip

Are there any jQuery plugins available that mimic the functionality of the tooltip dialog in the Flow App? (See screenshot here: ). I am currently working on a web app that requires a lot of tooltip dialogs. If there isn't a plugin available, could s ...