キャンペーンサイトに使えそう!<CANVAS>タグを使った画像のスクラッチ表現

<canvas>タグを使った、画像のスクラッチ表現を紹介します。

キャンペーンサイトに使えそう!<CANVAS>タグを使った画像のスクラッチ表現

キャンペーンサイトに使えそう!<CANVAS>タグを使った画像のスクラッチ表現

Scratch Reveal with <canvas>は、<canvas>タグとJSで実装する、画像のスクラッチ表現です。

カラフルな写真にマウスを載せて、ドラッグすると、スクラッチを削るようにグレースケースの写真が現れます。

キャンペーンサイトに使えそう!タグを使った画像のスクラッチ表現

もちろん、デフォルトをグレースケールの写真にして、スクラッチでカラフルな写真を表示させることも可能です。

例えば、キャンペーンサイトなどで、画像にシリアルコードや当たり、ハズレのマークを埋め込んでおいて、ユーザーが画像を削ると表示される、という使い方ができそうです。

実装方法

デフォルトに表示される画像と、スクラッチで削った後に表示される画像の2枚を用意しておきます。

HTML

<canvas>を用意します。

<figure id="bridgeContainer">
  <canvas id="bridge" width="750" height="465"></canvas>
  <figcaption>Downtown Calgary in 2013 and 1943; mouse down or touch on photo to reveal</figcaption>
</figure>

CSS

背景のbackground-imagehttps://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/calgary-bridge-1943.jpgの部分が最初に表示される画像です。

body { margin: 0; }

#bridge {
  display: block;
  margin: 0 auto;
  background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/calgary-bridge-1943.jpg');
  background-image: -webkit-image-set(url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/calgary-bridge-1943.jpg') 1x, url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/calgary-bridge-1943-2x.jpg') 2x );
  background-size: cover;
  width: 100%;
  max-width: 750px;
  height: auto;
  cursor: crosshair;
  cursor: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/circular-cursor.png) 53 53, crosshair;
}
#bridgeContainer { 
  text-align: center;
  font-family: Avenir, sans-serif;
}
#bridgeContainer figcaption { 
  margin-top: 2rem; 
}

JS

元の画像のURLを書き換える形で、スクラッチ後に表示する画像のURLを指定します。img.loc = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/';の部分で、デフォルトの画像URLの内、書き換えない部分を指定します。img.filename = 'calgary-bridge-2013.jpg';の部分で、デフォルトの画像URLの内、書き換える部分を指定します。

var bridge = document.getElementById("bridge"),
bridgeCanvas = bridge.getContext('2d'),
brushRadius = (bridge.width / 100) * 5,
img = new Image();

if (brushRadius < 50) { brushRadius = 50 }

img.onload = function(){  
  bridgeCanvas.drawImage(img, 0, 0, bridge.width, bridge.height);
}
img.loc = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/';
img.filename = 'calgary-bridge-2013.jpg';
if (window.devicePixelRatio >= 2) {
  var nameParts = img.filename.split('.');
  img.src = img.loc + nameParts[0]+"-2x"+"."+nameParts[1];
} else {
  img.src = img.loc + img.filename;
}

function detectLeftButton(event) {
  if ('buttons' in event) {
    return event.buttons === 1;
  } else if ('which' in event) {
    return event.which === 1;
  } else {
    return event.button === 1;
  }
}

function getBrushPos(xRef, yRef) {
  var bridgeRect = bridge.getBoundingClientRect();
  return {
    x: Math.floor((xRef-bridgeRect.left)/(bridgeRect.right-bridgeRect.left)*bridge.width),
    y: Math.floor((yRef-bridgeRect.top)/(bridgeRect.bottom-bridgeRect.top)*bridge.height)
  };
}
      
function drawDot(mouseX,mouseY){
  bridgeCanvas.beginPath();
  bridgeCanvas.arc(mouseX, mouseY, brushRadius, 0, 2*Math.PI, true);
  bridgeCanvas.fillStyle = '#000';
  bridgeCanvas.globalCompositeOperation = "destination-out";
  bridgeCanvas.fill();
}

bridge.addEventListener("mousemove", function(e) {
  var brushPos = getBrushPos(e.clientX, e.clientY);
  var leftBut = detectLeftButton(e);
  if (leftBut == 1) {
    drawDot(brushPos.x, brushPos.y);
  }
}, false);

bridge.addEventListener("touchmove", function(e) {
  e.preventDefault();
  var touch = e.targetTouches[0];
  if (touch) {
  var brushPos = getBrushPos(touch.pageX, touch.pageY);
      drawDot(brushPos.x, brushPos.y);
  }
}, false);