1

I am using Magnify.js (http://mark-rolich.github.io/Magnifier.js/) in an older project and want to move away from it as it is pretty convoluted.

I attempted to build my own image zoom capabilities by refactoring + reading some articles on the subject but honestly the code wasn't going to go anywhere and thus I deleted it all due to its ineptitude at the time.

Anyway, to the issue at hand, here is what I am looking to make happen:

  1. I hover an image with a specific css class
  2. A canvas element appears on screen only if an image with that class is what is hovered
  3. A zoomed in version of an area around the cursor (100px x 100px) is shown inside the canvas element
  4. As the cursor is moved around the image the canvas updates in real time to show the zoomed in part of the new hover area as described above
  5. When the hovering stops, the canvas item is hidden once more

Sounds simple enough but it is far from it in how I am thinking about this issue.

So, my question, in short is: Are there any simple frameworks other than Magnify.js (as linked above) that you know of that I could check out or if it is simple enough to do and I am just over complicating it, how would you go about the issue?

1 Answers1

3

Well, using a framework use to be a good idea because it solves cross-browser issues and is a more full-featured solution than a code that you can make from scratch.

Anyway, if your needs are very limited you can do it yourself. BTW, you dind't tag the question with jQuery, but I will suppose that you are using it.

I don't think you need to use a canvas. Instead:

  1. Place the image twice, the second one inside a hidden container.
  2. Scale down the first one so you can use as a thumbnail.
  3. Leave the second one in its original size, but ensure the container has overflow: hidden.
  4. Create a mousemove event. It needs to make visible the container.
  5. Detect the position of the mouse inside the picture with e.pageX / e.pageY and $( element ).offset().
  6. Calculate the ratio between the area of the thumbnail and the original picture size.
  7. Every time you move the cursor, modify the margins of the original size picture (the one inside the container) according the calculated ratio.
  8. Create a mouseout event that hides the container.

Here you have a snippet:

var zoom_container_size = $( '.zoom_container').height();
var zoom_area_size = 100;
var zoom_radius = zoom_area_size / 2;

$( '.thumbnail' ).mousemove(function(e) {
    // Show original picture    
    var $original = $( '#' + this.id + '_original');
    var $container = $original.parent();
    $container.removeClass( 'hidden' );
    // Thumbnail
    var offset = $( this ).offset();
    var tX = e.pageX - offset.left;
    var tY = e.pageY - offset.top;
    // We stay inside the limits of the zoomable area
    tX = Math.max( zoom_radius, Math.min( $( this ).width() - zoom_radius, tX ) );
    tY = Math.max( zoom_radius, Math.min( $( this ).height() - zoom_radius, tY ) );
    // Ratios
    var ratioX = ( $original.width() - zoom_container_size) / ( $( this ).width() - zoom_area_size );
    var ratioY = ( $original.height() - zoom_container_size) / ( $( this ).height() - zoom_area_size );
    // Margin to be set in the original    
    var moX = -Math.floor( ( tX - zoom_radius ) * ratioX );
    var moY = -Math.floor( ( tY - zoom_radius ) * ratioY );
    // Apply zoom efect
    $original.css( 'marginLeft', moX );
    $original.css( 'marginTop', moY );
    // Log values
    $('#ratios').html( 'Ratio X: <b>' + ratioX + '</b><br>Ratio Y: <b>' +  ratioY + '</b>' );
    $('#coordinates_thumbnail').html( 'tX: <b>' + tX + '</b><br>tY: <b>' +  tY + '</b>' );
    $('#coordinates_original' ).html( 'Margin left: <b>' + Math.round(moX) + '</b><br>Margin top: <b>' +  moY + '</b>' );
});

$( '.thumbnail' ).mouseout(function(e) {
    var $original = $( '#' + this.id + '_original');
    var $container = $original.parent();
    $container.addClass( 'hidden' );
});
.main_container div {
    display: inline-block;
}
.thumbnail {
    height: 200px;
}
div.zoom_container {
    width: 200px;
    height: 200px;
    overflow: hidden;
}
.zoom_container.hidden {
    display: none;    
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
A beautiful pic from <a href="https://commons.wikimedia.org/wiki/File:Talv_V%C3%A4ike-Taevaskojas.jpg">Külli Kolina</a>.

<div id="zoom_area"></div>
<div class="main_container">
    <img id="forest" class="thumbnail" src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Talv_V%C3%A4ike-Taevaskojas.jpg/640px-Talv_V%C3%A4ike-Taevaskojas.jpg">
    <div class="zoom_container hidden">
        <img id="forest_original" class="original" src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Talv_V%C3%A4ike-Taevaskojas.jpg/640px-Talv_V%C3%A4ike-Taevaskojas.jpg">
    </div>
</div>
<hr><span id="ratios">Ratios</span>
<hr><span id="coordinates_thumbnail">Coordinates</span>
<hr><span id="coordinates_original">Negative margin</span>

There is a lot of things that can be optimized in this code (mainly related to get some of the work out of the event handler) to get a smoother effect, but you have now a base to start to work on. If you are really concern about performance you can read this other answer (the topic is different but most of the ideas apply in the same way).

Hope it helps!

Community
  • 1
  • 1
David
  • 6,695
  • 3
  • 29
  • 46