HTML5 Game - Creating an image magnifier

Introduction

The following code shows how to create an image magnifier.

It cuts out a section of a small image and displays the enlarged one on the canvas.

Demo

ResultView the demo in separate window

<!DOCTYPE HTML>
<html>
    <head>
<script>
class EventManager{//from ww w. j  av  a 2s  .com
   constructor(canvasId){
    this.canvas = document.getElementById(canvasId);
    this.context = this.canvas.getContext("2d");
    this.drawStage = undefined;
    this.listening = false;
    
    // desktop flags
    this.mousePos = null;
    this.mouseDown = false;
    this.mouseUp = false;
    this.mouseOver = false;
    this.mouseMove = false;
    
    // mobile flags
    this.touchPos = null;
    this.touchStart = false;
    this.touchMove = false;
    this.touchEnd = false;
    
    // Region Events
    this.currentRegion = null;
    this.regionIndex = 0;
    this.lastRegionIndex = -1;
    this.mouseOverRegionIndex = -1;
  }
  getContext(){
    return this.context;
  }

  getCanvas(){
    return this.canvas;
  }
  clear(){
    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
  }
  getCanvasPos = function(){
    let obj = this.getCanvas();
    let top = 0;
    let left = 0;
    while (obj.tagName != "BODY") {
        top += obj.offsetTop;
        left += obj.offsetLeft;
        obj = obj.offsetParent;
    }
    return {
        top: top,
        left: left
    };
  }
  setDrawStage(func){
    this.drawStage = func;
    this.listen();
  }
  reset(evt){
    if (!evt) {
        evt = window.event;
    }
    
    this.setMousePosition(evt);
    this.setTouchPosition(evt);
    this.regionIndex = 0;
    
    if (this.drawStage !== undefined) {
        this.drawStage();
    }
    
    // desktop flags
    this.mouseOver = false;
    this.mouseMove = false;
    this.mouseDown = false;
    this.mouseUp = false;
    
    // mobile touch flags
    this.touchStart = false;
    this.touchMove = false;
    this.touchEnd = false;
  }  
  listen(){
    let that = this;
    
    if (this.drawStage !== undefined) {
        this.drawStage();
    }
    
    // desktop events
    this.canvas.addEventListener("mousedown", function(evt){
        that.mouseDown = true;
        that.reset(evt);
    }, false);
    
    this.canvas.addEventListener("mousemove", function(evt){
        that.reset(evt);
    }, false);
    
    this.canvas.addEventListener("mouseup", function(evt){
        that.mouseUp = true;
        that.reset(evt);
    }, false);
    
    this.canvas.addEventListener("mouseover", function(evt){
        that.reset(evt);
    }, false);
    
    this.canvas.addEventListener("mouseout", function(evt){
        that.mousePos = null;
    }, false);
    
    // mobile events
    this.canvas.addEventListener("touchstart", function(evt){
        evt.preventDefault();
        that.touchStart = true;
        that.reset(evt);
    }, false);
    
    this.canvas.addEventListener("touchmove", function(evt){
        evt.preventDefault();
        that.reset(evt);
    }, false);
    
    this.canvas.addEventListener("touchend", function(evt){
        evt.preventDefault();
        that.touchEnd = true;
        that.reset(evt);
    }, false);
  }
  getMousePos(evt){
    return this.mousePos;
  }
  getTouchPos(evt){
    return this.touchPos;
  }
  setMousePosition(evt){
    let mouseX = evt.clientX - this.getCanvasPos().left + window.pageXOffset;
    let mouseY = evt.clientY - this.getCanvasPos().top + window.pageYOffset;
    this.mousePos = {
        x: mouseX,
        y: mouseY
    };
  }
  setTouchPosition(evt){
    if (evt.touches !== undefined && evt.touches.length == 1) { // Only deal with one finger
        let touch = evt.touches[0]; // Get the information for finger #1
        let touchX = touch.pageX - this.getCanvasPos().left + window.pageXOffset;
        let touchY = touch.pageY - this.getCanvasPos().top + window.pageYOffset;
        
        this.touchPos = {
            x: touchX,
            y: touchY
        };
    }
  }
  beginRegion = function(){
    this.currentRegion = {};
    this.regionIndex++;
  }
  addRegionEventListener = function(type, func){
     let event = (type.indexOf('touch') == -1) ? 'on' + type : type;
     this.currentRegion[event] = func;
  }
  closeRegion(){
    let pos = this.touchPos || this.mousePos;
    
    if (pos !== null && this.context.isPointInPath(pos.x, pos.y)) {
        if (this.lastRegionIndex != this.regionIndex) {
            this.lastRegionIndex = this.regionIndex;
        }
        
        // handle onmousedown
        if (this.mouseDown && this.currentRegion.onmousedown !== undefined) {
            this.currentRegion.onmousedown();
            this.mouseDown = false;
        }
        
        // handle onmouseup
        else if (this.mouseUp && this.currentRegion.onmouseup !== undefined) {
            this.currentRegion.onmouseup();
            this.mouseUp = false;
        }
        
        // handle onmouseover
        else if (!this.mouseOver && this.regionIndex != this.mouseOverRegionIndex && this.currentRegion.onmouseover !== undefined) {
            this.currentRegion.onmouseover();
            this.mouseOver = true;
            this.mouseOverRegionIndex = this.regionIndex;
        }
        
        // handle onmousemove
        else if (!this.mouseMove && this.currentRegion.onmousemove !== undefined) {
            this.currentRegion.onmousemove();
            this.mouseMove = true;
        }
        
        // handle touchstart
        if (this.touchStart && this.currentRegion.touchstart !== undefined) {
            this.currentRegion.touchstart();
            this.touchStart = false;
        }
        
        // handle touchend
        if (this.touchEnd && this.currentRegion.touchend !== undefined) {
            this.currentRegion.touchend();
            this.touchEnd = false;
        }
        
        // handle touchmove
        if (!this.touchMove && this.currentRegion.touchmove !== undefined) {
            this.currentRegion.touchmove();
            this.touchMove = true;
        }
        
    }
    else if (this.regionIndex == this.lastRegionIndex) {
        this.lastRegionIndex = -1;
        this.mouseOverRegionIndex = -1;
        
        // handle mouseout condition
        if (this.currentRegion.onmouseout !== undefined) {
            this.currentRegion.onmouseout();
        }
    }
}
}

    function loadImages(sources, callback){
        let loadedImages = 0;
        let numImages = 0;
        let images = {};
        // get num of sources
        for (let src in sources) {
            numImages++;
        }
        // load images
        for (let src in sources) {
            images[src] = new Image();
            images[src].onload = function(){
                // call callback function when images
                // have loaded
                if (++loadedImages >= numImages) {
                    callback(images);
                }
            };
            images[src].src = sources[src];
        }
    }
    
    function drawMagnifier(config){
        let context = config.context;
        let images = config.images;
        let mousePos = config.mousePos;
        let imageX = config.imageX;
        let imageY = config.imageY;
        let magWidth = config.magWidth;
        let magHeight = config.magHeight;
        let smallWidth = config.smallWidth;
        let smallHeight = config.smallHeight;
        let largeWidth = config.largeWidth;
        let largeHeight = config.largeHeight;
        

        let sourceX = ((mousePos.x - imageX) * largeWidth / smallWidth) - magWidth / 2;
        let sourceY = ((mousePos.y - imageY) * largeHeight / smallHeight) - magHeight / 2;
        let destX = mousePos.x - magWidth / 2;
        let destY = mousePos.y - magHeight / 2;
        let viewWidth = magWidth;
        let viewHeight = magHeight;
        let viewX = destX;
        let viewY = destY;
        let drawMagImage = true;
        
        if (sourceX < 0) {
            if (sourceX > -1 * magWidth) {
                let diffX = -1 * sourceX;
                viewX += diffX;
                viewWidth -= diffX;
                sourceX = 0;
            }
            else {
                drawMagImage = false;
            }
        }
        
        if (sourceX > largeWidth - magWidth) {
            if (sourceX < largeWidth) {
                viewWidth = largeWidth - sourceX;
            }
            else {
                drawMagImage = false;
            }
        }
        
        if (sourceY < 0) {
            if (sourceY > -1 * magHeight) {
                let diffY = -1 * sourceY;
                viewY += diffY;
                viewHeight -= diffY;
                sourceY = 0;
            }
            else {
                drawMagImage = false;
            }
        }
        
        if (sourceY > largeHeight - magHeight) {
            if (sourceY < largeHeight) {
                viewHeight = largeHeight - sourceY;
            }
            else {
                drawMagImage = false;
            }
        }
        
        context.beginPath();
        context.fillStyle = "white";
        context.fillRect(destX, destY, magWidth, magHeight);
        
        if (drawMagImage) {
            context.beginPath();
            context.drawImage(images.jet1Image, sourceX, sourceY, viewWidth, viewHeight, viewX, viewY, viewWidth, viewHeight);
        }
        
        // draw magnifier border
        context.beginPath();
        context.lineWidth = 2;
        context.strokeStyle = "black";
        context.strokeRect(destX, destY, magWidth, magHeight);
    }
    
    function drawImages(images){
        let events = new EventManager("myCanvas");
        let canvas = events.getCanvas();
        let context = events.getContext();
        
        // define magnifier dependencies
        let imageX = canvas.width / 2 - images.jet2Image.width / 2;
        let imageY = canvas.height / 2 - images.jet2Image.height / 2;
        let magWidth = 200;
        let magHeight = 150;
        let smallWidth = images.jet2Image.width;
        let smallHeight = images.jet2Image.height;
        let largeWidth = images.jet1Image.width;
        let largeHeight = images.jet1Image.height;
        
        events.setDrawStage(function(){
            let mousePos = events.getMousePos();
            this.clear();
            
            context.drawImage(images.jet2Image, imageX, imageY, smallWidth, smallHeight);
            // draw rectangular region for image
            context.beginPath();
            context.lineWidth = 2;
            context.strokeStyle = "black";
            context.strokeRect(imageX, imageY, smallWidth, smallHeight);
            context.closePath();
            
            if (mousePos !== null) {
                drawMagnifier({
                    context: context,
               images: images,
                    mousePos: mousePos,
                    imageX: imageX,
                    imageY: imageY,
                    magWidth: magWidth,
                    magHeight: magHeight,
                    smallWidth: smallWidth,
                    smallHeight: smallHeight,
                    largeWidth: largeWidth,
                    largeHeight: largeHeight
                });
            }
        });
        
        canvas.addEventListener("mouseout", function(){
            events.drawStage();
        }, false);
    }
    
    window.onload = function(){
        let sources = {
            jet2Image: "http://java2s.com/style/demo/jet2.png",
            jet1Image: "http://java2s.com/style/demo/jet2.png"
        };
        
        loadImages(sources, drawImages);
    };
</script>
    </head>
    <body>
        <canvas id="myCanvas" width="600" height="250" style="border:1px solid black;">
        </canvas>
    </body>
</html>

Related Topic