Crafting an interactive saturation effect for mouseover interactions in a circular design

I'm looking to create a unique hover effect for my images. I have both a desaturated version and a full color version of the same image. My idea is to have mousing over the desaturated image reveal a circle spotlighting the color version underneath, almost like shining a light on the desatrated image to show its true colors. When the mouse moves away, it would fade back to its original desaturated state.

While flash could be an option, I want to achieve this effect using JavaScript and CSS. It should also gracefully degrade to just a regular image if JavaScript is disabled and be responsive in terms of width.

Answer №1

Creating Rounded Divs with CSS

The possibilities of CSS3's border-radius are endless when it comes to design. One interesting usage involves creating a round div acting as an image spotlight, overlaying the main image and adjusting its position based on mouse movements. Check out this JSFiddle Demo for a visual representation.

In the realm of CSS3, achieving softened edges in spotlights is not straightforward; it demands support for opacity gradients which can be emulated by incorporating multiple elements with varying radius and opacity levels. An example showcasing softened edges can be viewed in this Updated demo with softened edges.

The adjusted variables in the updated demo dictate the spotlight's size and level of softness:

var spotlightDiameter = 150;      // Base size (excluding soft edge)
var numSpotlightLayers = 6;       // Increased layers result in softer edges
var spotlightLayerThickness = 2;  // Thinner thickness yields subtle softening

To witness ripples in the spotlight effect, refer to this modified demo. By enhancing layer thickness, the functionality becomes more evident.

A simplified version of the code featuring sharp-edged spotlights is depicted below:

HTML

<div class="content">
    <div class="spotlight"></div>
</div>

CSS

.content {
    position: relative;
    width: 640px;
    height: 480px;
    background: url(desaturated.jpg) no-repeat 0 0;
    overflow: hidden;
}
.spotlight {
    display: none;
    position: absolute;
    background: url(overly_saturated.jpg) no-repeat 0 0;
}

jQuery

var spotlightDiameter = 150;

// Update the spotlight position on mousemove
$('.content').on('mousemove', function(e){
    var center = {x: e.pageX - this.offsetLeft,
                  y: e.pageY - this.offsetTop};
    var x = center.x - (spotlightDiameter >> 1);
    var y = center.y - (spotlightDiameter >> 1);

    $('.spotlight').css({left: x + 'px', top: y + 'px',
                         backgroundPosition: -x + 'px ' + -y + 'px'}).show();
});

// Hide the spotlight on mouseout
$('.content').on('mouseout', function(e){
    $('.spotlight').hide();
});

// Initialize the spotlight
$(document).ready(function(){
    $('.spotlight').width(spotlightDiameter + 'px')
                   .height(spotlightDiameter + 'px')
                   .css({borderRadius: (spotlightDiameter >> 1) + 'px'});
});

Variations Using Different Technologies

The concept can also be approached utilizing HTML5 Canvas or SVG. Below is a comparison of browser support across diverse implementations:

In summary, for solutions including border-radius and HTML5 Canvas, compatibility is unattainable with IE8 and predecessors. Though Android backing may not be crucial considering the mouse-centric nature of the operation.

Answer №2

Combine two SVG <image> elements stacked directly on top of each other. The bottom image should be in greyscale while the top image is colored. Use a clipPath on the colored image and adjust the transform on the clipping path to reveal different sections of the upper image.

Check out this Simple Demo: http://jsfiddle.net/hZgkz/

SVG:

<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="250px">
  <defs>
    <image id="im" width="500" height="500"
     xlink:href="http://www.nyweamet.org/wp-content/uploads/2011/09/0942a__grandCentralStationExterior.jpg"/>
    <clipPath id="clip">
      <path id="path" transform="translate(40,60)"
            d="M60,0 A30,30 1,0,0 60,120 30,30 1,0,0, 60,0"/>
    </clipPath>
  </defs>
  <use id="clippedImage" xlink:href="#im" clip-path="url(#clip)"/>
</svg>

Here's the JavaScript code that animates the movement of the circle:

var tx = document.querySelector('#path').transform.baseVal.getItem(0);
setInterval(function(){
  var ms = (new Date)*1;
  tx.matrix.e = Math.sin(ms/812)*150 + 160;
  tx.matrix.f = Math.cos(ms/437)*60 + 70;
},50); 

All you need to do is track the mouse movements and adjust the translation accordingly.

Answer №3

To achieve the desired result, you can utilize CSS. Below is a demonstration provided in a small fiddle: http://jsfiddle.net/sandro_paganotti/k3AmZ/

Below is the code snippet:

HTML

<figure data-desaturated></figure>
<figure data-original></figure>

CSS

figure{ 
    width: 550px; height: 360px;
    position: absolute; top: 0; left: 0;
    margin: 0; padding: 0; 
    background-position: 50% 50%;
    background-repeat: no-repeat;
    background-image: url('yourimage.png');
}

figure[data-desaturated]{
    -webkit-filter: grayscale(0.9);
}

figure[data-original]{
    width: 360px;
    left: 95px;
    border-radius: 180px;
    opacity: 0;
    transition: opacity 0.4s;
}

figure[data-desaturated]:hover + figure[data-original],
figure[data-original]:hover{
    opacity: 1;
}

A transition has been added to improve user interaction.

Update

An updated version that responds to mouse movements can be found here: http://jsfiddle.net/sandro_paganotti/k3AmZ/3/

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

Importing an Excel file in .xlsx format cannot be done through AJAX JQUERY

I am trying to display the content of an Excel file when a button is clicked. It works fine when I change the extension to .csv, but when I change it to .xlsx, I get a character type error that looks like "y!+EfMykK5=|t G)s墙UtB)". These strange charact ...

Having difficulty entering text into a "Search Input Field" that is a react component in testcafe

Struggling to input text in a "Type to search dropdown" that is a react component. While able to click on the component, typing any text seems to be an issue. Listed below is an example of the code: import { Selector } from 'testcafe'; test(&ap ...

Tutorial on Removing and Re-Adding HTML Elements

Currently, I am utilizing Jquery to temporarily remove an element from the DOM. This specific element consists of an HTML5 video element. However, upon re-adding this element back into the DOM, the video is unable to play and the element appears as blank o ...

Can you help me with compiling Twitter Bootstrap 3.0 on my Windows 8?

Can anyone guide me on compiling Twitter Bootstrap using Less on a Windows machine? I tried following a tutorial but ran into issues with installing lessc (it was not in the npm registry). Also, the tutorial was for BS2 and not 3.0 which made me skeptical ...

Artwork - Circular design disappears without warning

While working on a clock project purely for enjoyment, I noticed that the minute arc disappears from the canvas as soon as a new minute begins. Any idea why this is happening? Check out the clock in action: https://jsfiddle.net/y0bson6f/ HTML <canvas ...

When I use the Put method in Express, I receive a 200 status code, but no changes

Hello everyone, I recently attempted to implement my update function and tested it using Postman. I wanted to update the firstName field, but despite receiving a "HTTP/1.1" 200 response in the console, nothing was actually updated. This is the response bo ...

Tips for updating VUE's main.js file to incorporate the routers/index.js configuration

What is the reason for the difference in syntax between the VUE UI main.js code generated by CLI/3 and the older version, and how does it function? What are the various components of the new syntax and how do they work? sync(store, router) // for vuex-rou ...

Building an anchor tag that employs the HTTP DELETE method within an Express.js app

Recently, I delved into using express.js with handlebars.js as my template engine. One task I wanted to tackle was creating a delete link that followed RESTful principles and used the HTTP DELETE verb instead of GET. After some trial and error, I discover ...

Data not being properly set in the form

Check out this chunk of HTML code: <html> <head> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"> </script> <script> function getCords(){ ...

Issue with parentNode.replaceChild not functioning properly in Internet Explorer 6

In my HTML file created with FCK editor, I attempted to replace an existing table element with a new one using the parentNode.replaceChild method. While this change was successful in Internet Explorer 8, it resulted in errors when viewed in IE6 and IE7. ...

Executing a custom object function in AngularJS by using the ng-click directive

As I navigate my way through AngularJS, I find myself grappling with the concept of calling a custom method of an object and wonder if there's a simpler approach: https://jsfiddle.net/f4ew9csr/3/ <div ng-app="myApp" ng-controller="myCtrl as myCtr ...

Is there a way to convert an empty string to zero in MySQL?

Can you help with answering my question? My question pertains to saving an empty string "" value in my table and storing it as a 0 value in the MySQL database. Here is a visual representation: Table -> MySQL "" 0 Thank you for your assi ...

I am encountering a continuous css ParserError while trying to compile my react project

I'm having trouble with the compilation of my React project. While everything runs smoothly with npm start, I encounter an error during compilation: npm run build <a href="/cdn-cgi/l/email-protection" class="__cf_ema ...

Curved edges on a text box featuring a scroll bar

I'm facing an issue with my website where I have a large amount of text in an html textarea that requires a scroll bar. The problem is, I'd like to add rounded corners to the textarea, but it doesn't look good with the scroll bar. Below is ...

gRaphael - the struggle of animating a line chart

Encountering an issue with the gRaphael javascript line chart library. Creating a line chart from a CSV file with five columns (# of minutes, time, waiting time, in treatment, closed, in location). Previously drew full chart without animation successfull ...

Include an element in a secondary list based on its position in the initial list

Having 2 lists presents a challenge. An Angular service is utilized with a splice-based method to remove items from the first list (named "items") according to their index through a ng-click action. service.removeItem = function (itemIndex) { items ...

Constantly positioning the text cursor over the Textbox

I am currently in the process of developing a webpage that will feature only one text box for displaying information based on the input data provided. Our strategy involves utilizing either a Barcode Scanner or Magnetic Swipe as well as a Touch Screen Moni ...

Discover the exact location of an HTML element within an iframe

I am currently attempting to determine the position of an element that is within an iframe. I have written the following code for this purpose: // Custom function to calculate the position of an element on the page function getElementPosition(elem){ var ...

How can 'this' be converted from D3 JavaScript to TypeScript?

In JavaScript, 'this' has a different meaning compared to TypeScript, as explained in this informative article 'this' in TypeScript. The JavaScript code below is used to create a thicker stroke on the selected node and give smaller stro ...

A guide on using Sinon to mock a custom $http transform

Exploring the proper method for mocking an http post with a custom transform in Angular using the Sinon mocking framework. In my CoffeeScript Sinon unit test setup, I define mocks like this: beforeEach module(($provide) -> mockHttp = {} $provide.value ...