亚洲最大看欧美片,亚洲图揄拍自拍另类图片,欧美精品v国产精品v呦,日本在线精品视频免费

  • 站長資訊網(wǎng)
    最全最豐富的資訊網(wǎng)站

    Canvas實(shí)現(xiàn)放大鏡效果

      圖片放大鏡

      效果

    Canvas實(shí)現(xiàn)放大鏡效果

      在線演示 源碼

      原理

      首先選擇圖片的一塊區(qū)域,然后將這塊區(qū)域放大,然后再繪制到原先的圖片上,保證兩塊區(qū)域的中心點(diǎn)一致, 如下圖所示:

    Canvas實(shí)現(xiàn)放大鏡效果

      初始化

    <canvas id="canvas" width="500" height="500">  </canvas>    <img src="image.png" style="display: none" id="img">

      獲得 canvas 和 image 對象,這里使用 Canvas實(shí)現(xiàn)放大鏡效果 標(biāo)簽預(yù)加載圖片, 關(guān)于圖片預(yù)加載可以看這里

    var canvas = document.getElementById("canvas");  var context = canvas.getContext("2d");  var img = document.getElementById("img");

      設(shè)置相關(guān)變量

    // 圖片被放大區(qū)域的中心點(diǎn),也是放大鏡的中心點(diǎn)  var centerPoint = {};  // 圖片被放大區(qū)域的半徑  var originalRadius = 100;  // 圖片被放大區(qū)域  var originalRectangle = {};  // 放大倍數(shù)  var scale = 2;  // 放大后區(qū)域  var scaleGlassRectangle

      畫背景圖片

    function drawBackGround() {      context.drawImage(img, 0, 0);  }

      計算圖片被放大的區(qū)域的范圍

      這里我們使用鼠標(biāo)的位置作為被放大區(qū)域的中心點(diǎn)(放大鏡隨著鼠標(biāo)移動而移動),因為 canvas 在畫圖片的時候,需要知道左上角的坐標(biāo)以及區(qū)域的寬高,所以這里我們計算區(qū)域的范圍

    function calOriginalRectangle(point) {      originalRectangle.x = point.x - originalRadius;      originalRectangle.y = point.y - originalRadius;      originalRectangle.width = originalRadius * 2;      originalRectangle.height = originalRadius * 2;  }


      繪制放大鏡區(qū)域

      裁剪區(qū)域

      放大鏡一般是圓形的,這里我們使用 clip 函數(shù)裁剪出一個圓形區(qū)域,然后在該區(qū)域中繪制放大后的圖。一旦裁減了某個區(qū)域,以后所有的繪圖都會被限制的這個區(qū)域里,這里我們使用 save 和 restore 方法清除裁剪區(qū)域的影響。save 保存當(dāng)前畫布的一次狀態(tài),包含 canvas 的上下文屬性,例如 style,lineWidth 等,然后會將這個狀態(tài)壓入一個堆棧。restore 用來恢復(fù)上一次 save 的狀態(tài),從堆棧里彈出最頂層的狀態(tài)。

    context.save();  context.beginPath();  context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);  context.clip();  ......  context.restore();

      計算放大鏡區(qū)域

      通過中心點(diǎn)、被放大區(qū)域的寬高以及放大倍數(shù),獲得區(qū)域的左上角坐標(biāo)以及區(qū)域的寬高。

    scaleGlassRectangle = {      x: centerPoint.x - originalRectangle.width * scale / 2,      y: centerPoint.y - originalRectangle.height * scale / 2,      width: originalRectangle.width * scale,      height: originalRectangle.height * scale  }

      繪制圖片

      在這里我們使用 context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height); 方法,將 canvas 自身作為一副圖片,然后取被放大區(qū)域的圖像,將其繪制到放大鏡區(qū)域里。

    context.drawImage(canvas,      originalRectangle.x, originalRectangle.y,      originalRectangle.width, originalRectangle.height,      scaleGlassRectangle.x, scaleGlassRectangle.y,      scaleGlassRectangle.width, scaleGlassRectangle.height  );

      繪制放大邊緣

      createRadialGradient 用來繪制漸變圖像

    context.beginPath();  var gradient = context.createRadialGradient(      centerPoint.x, centerPoint.y, originalRadius - 5,      centerPoint.x, centerPoint.y, originalRadius);  gradient.addColorStop(0, 'rgba(0,0,0,0.2)');  gradient.addColorStop(0.80, 'silver');  gradient.addColorStop(0.90, 'silver');  gradient.addColorStop(1.0, 'rgba(150,150,150,0.9)');    context.strokeStyle = gradient;  context.lineWidth = 5;  context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);  context.stroke();

      添加鼠標(biāo)事件

      為 canvas 添加鼠標(biāo)移動事件

    canvas.onmousemove = function (e) {      ......  }

      轉(zhuǎn)換坐標(biāo)

      鼠標(biāo)事件獲得坐標(biāo)一般為屏幕的或者 window 的坐標(biāo),我們需要將其裝換為 canvas 的坐標(biāo)。getBoundingClientRect 用于獲得頁面中某個元素的左,上,右和下分別相對瀏覽器視窗的位置。

    function windowToCanvas(x, y) {      var bbox = canvas.getBoundingClientRect();      return {x: x - bbox.left, y: y - bbox.top}  }

      修改鼠標(biāo)樣式

      我們可以通過 css 來修改鼠標(biāo)樣式

    #canvas {      display: block;      border: 1px solid red;      margin: 0 auto;      cursor: crosshair;  }

      圖表放大鏡

      我們可能基于 canvas 繪制一些圖表或者圖像,如果兩個元素的坐標(biāo)離得比較近,就會給元素的選擇帶來一些影響,例如我們畫兩條線,一個線的坐標(biāo)是(200.5, 400) -> (200.5, 200),另一個線的坐標(biāo)為 (201.5, 400) -> (201.5, 20),那么這兩條線幾乎就會重疊在一起,如下圖所示:

    Canvas實(shí)現(xiàn)放大鏡效果

      使用圖表放大鏡的效果

    Canvas實(shí)現(xiàn)放大鏡效果

      在線演示 源碼

      原理

      類似于地圖中的圖例,放大鏡使用較為精確的圖例,如下圖所示:

    Canvas實(shí)現(xiàn)放大鏡效果

      在放大鏡坐標(biāo)系統(tǒng)中,原始的區(qū)域會變大,如下圖所示

    Canvas實(shí)現(xiàn)放大鏡效果

      繪制原始線段


      首先創(chuàng)建一個線段對象

    function Line(xStart, yStart, xEnd, yEnd, index, color) {      // 起點(diǎn)x坐標(biāo)      this.xStart = xStart;      // 起點(diǎn)y坐標(biāo)      this.yStart = yStart;      // 終點(diǎn)x坐標(biāo)      this.xEnd = xEnd;      // 終點(diǎn)y坐標(biāo)      this.yEnd = yEnd;      // 用來標(biāo)記是哪條線段      this.index = index;      // 線段顏色      this.color = color;  }

      初始化線段

     

    // 原始線段  var chartLines = new Array();  // 處于放大鏡中的原始線段  var glassLines;  // 放大后的線段  var scaleGlassLines;  // 位于放大鏡中的線段數(shù)量  var glassLineSize;    function initLines() {        var line;      line = new Line(200.5, 400, 200.5, 200, 0, "#888");      chartLines.push(line);      line = new Line(201.5, 400, 201.5, 20, 1, "#888");      chartLines.push(line);          glassLineSize = chartLines.length;      glassLines = new Array(glassLineSize);      for (var i = 0; i < glassLineSize; i++) {          line = new Line(0, 0, 0, 0, i);          glassLines[i] = line;      }        scaleGlassLines = new Array(glassLineSize);      for (var i = 0; i < glassLineSize; i++) {          line = new Line(0, 0, 0, 0, i);          scaleGlassLines[i] = line;      }  }

      繪制線段

    function drawLines() {      var line;      context.lineWidth = 1;        for (var i = 0; i < chartLines.length; i++) {          line = chartLines[i];          context.beginPath();          context.strokeStyle = line.color;          context.moveTo(line.xStart, line.yStart);          context.lineTo(line.xEnd, line.yEnd);          context.stroke();      }  }

      計算原始區(qū)域和放大鏡區(qū)域

    function calGlassRectangle(point) {      originalRectangle.x = point.x - originalRadius;      originalRectangle.y = point.y - originalRadius;      originalRectangle.width = originalRadius * 2;      originalRectangle.height = originalRadius * 2;        scaleGlassRectangle.width = originalRectangle.width * scale;      scaleGlassRectangle.height = originalRectangle.height * scale;      scaleGlassRectangle.x = originalRectangle.x + originalRectangle.width / 2 - scaleGlassRectangle.width / 2;      scaleGlassRectangle.y = originalRectangle.y + originalRectangle.height / 2 - scaleGlassRectangle.height / 2;        // 將值裝換為整數(shù)      scaleGlassRectangle.width = parseInt(scaleGlassRectangle.width);      scaleGlassRectangle.height = parseInt(scaleGlassRectangle.height);      scaleGlassRectangle.x = parseInt(scaleGlassRectangle.x);      scaleGlassRectangle.y = parseInt(scaleGlassRectangle.y);  }

      計算線段在新坐標(biāo)系統(tǒng)的位置

      由原理圖我們知道,放大鏡中使用坐標(biāo)系的圖例要比原始坐標(biāo)系更加精確,比如原始坐標(biāo)系使用 1:100,那么放大鏡坐標(biāo)系使用 1:10,因此我們需要重新計算線段在放大鏡坐標(biāo)系中的位置。同時為了簡便,我們將線段的原始坐標(biāo)進(jìn)行了轉(zhuǎn)化,減去原始區(qū)域起始的x值和y值,即將原始區(qū)域左上角的點(diǎn)看做為(0,0)。

    function calScaleLines() {      var xStart = originalRectangle.x;      var xEnd = originalRectangle.x + originalRectangle.width;      var yStart = originalRectangle.y;      var yEnd = originalRectangle.y + originalRectangle.height;      var line, gLine, sgLine;      var glassLineIndex = 0;      for (var i = 0; i < chartLines.length; i++) {          line = chartLines[i];            // 判斷線段是否在放大鏡中          if (line.xStart < xStart || line.xEnd > xEnd) {              continue;          }          if (line.yEnd > yEnd || line.yStart < yStart) {              continue;          }            gLine = glassLines[glassLineIndex];          sgLine = scaleGlassLines[glassLineIndex];          if (line.yEnd > yEnd) {              gLine.yEnd = yEnd;          }          if (line.yStart < yStart) {              gLine.yStart = yStart;          }            gLine.xStart = line.xStart - xStart;          gLine.yStart = line.yStart - yStart;          gLine.xEnd = line.xEnd - xStart;          gLine.yEnd = line.yEnd - yStart;            sgLine.xStart = parseInt(gLine.xStart * scale);          sgLine.yStart = parseInt(gLine.yStart * scale);          sgLine.xEnd = parseInt(gLine.xEnd * scale);          sgLine.yEnd = parseInt(gLine.yEnd * scale);          sgLine.color = line.color;          glassLineIndex++;      }      glassLineSize = glassLineIndex;  }

      繪制放大鏡中心點(diǎn)

      繪制放大鏡中心的瞄準(zhǔn)器

    function drawAnchor() {      context.beginPath();      context.lineWidth = 2;      context.fillStyle = "#fff";      context.strokeStyle = "#000";      context.arc(parseInt(centerPoint.x), parseInt(centerPoint.y), 10, 0, Math.PI * 2, false);        var radius = 15;      context.moveTo(parseInt(centerPoint.x - radius), parseInt(centerPoint.y));      context.lineTo(parseInt(centerPoint.x + radius), parseInt(centerPoint.y));      context.moveTo(parseInt(centerPoint.x), parseInt(centerPoint.y - radius));      context.lineTo(parseInt(centerPoint.x), parseInt(centerPoint.y + radius));      //context.fill();      context.stroke();  }

      繪制放大鏡

    function drawMagnifyingGlass() {        calScaleLines();        context.save();      context.beginPath();      context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);      context.clip();        context.beginPath();      context.fillStyle = "#fff";      context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);      context.fill();        context.lineWidth = 4;      for (var i = 0; i < glassLineSize; i++) {          context.beginPath();          context.strokeStyle = scaleGlassLines[i].color;          context.moveTo(scaleGlassRectangle.x + scaleGlassLines[i].xStart, scaleGlassRectangle.y + scaleGlassLines[i].yStart);          context.lineTo(scaleGlassRectangle.x + scaleGlassLines[i].xEnd, scaleGlassRectangle.y + scaleGlassLines[i].yEnd);          context.stroke();      }      context.restore();        context.beginPath();      var gradient = context.createRadialGradient(          parseInt(centerPoint.x), parseInt(centerPoint.y), originalRadius - 5,          parseInt(centerPoint.x), parseInt(centerPoint.y), originalRadius);        gradient.addColorStop(0.50, 'silver');      gradient.addColorStop(0.90, 'silver');      gradient.addColorStop(1, 'black');      context.strokeStyle = gradient;      context.lineWidth = 5;      context.arc(parseInt(centerPoint.x), parseInt(centerPoint.y), originalRadius, 0, Math.PI * 2, false);      context.stroke();        drawAnchor();  }

      添加事件

      鼠標(biāo)拖動

      鼠標(biāo)移動到放大鏡上,然后按下鼠標(biāo)左鍵,可以拖動放大鏡,不按鼠標(biāo)左鍵或者不在放大鏡區(qū)域都不可以拖動放大鏡。

      為了實(shí)現(xiàn)上面的效果,我們要實(shí)現(xiàn)3種事件 mousedown, mousemove, 'mouseup', 當(dāng)鼠標(biāo)按下時,檢測是否在放大鏡區(qū)域,如果在,設(shè)置放大鏡可以移動。鼠標(biāo)移動時更新放大鏡中興點(diǎn)的坐標(biāo)。鼠標(biāo)松開時,設(shè)置放大鏡不可以被移動。

    canvas.onmousedown = function (e) {      var point = windowToCanvas(e.clientX, e.clientY);      var x1, x2, y1, y2, dis;        x1 = point.x;      y1 = point.y;      x2 = centerPoint.x;      y2 = centerPoint.y;      dis = Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2);      if (dis < Math.pow(originalRadius, 2)) {          lastPoint.x = point.x;          lastPoint.y = point.y;          moveGlass = true;      }  }    canvas.onmousemove = function (e) {      if (moveGlass) {          var xDis, yDis;          var point = windowToCanvas(e.clientX, e.clientY);          xDis = point.x - lastPoint.x;          yDis = point.y - lastPoint.y;          centerPoint.x += xDis;          centerPoint.y += yDis;          lastPoint.x = point.x;          lastPoint.y = point.y;          draw();      }  }    canvas.onmouseup = function (e) {      moveGlass = false;  }

      鼠標(biāo)雙擊

      當(dāng)移動到對應(yīng)的線段上時,鼠標(biāo)雙擊可以選擇該線段,將該線段的顏色變?yōu)榧t色。

    canvas.ondblclick = function (e) {      var xStart, xEnd, yStart, yEnd;      var clickPoint = {};      clickPoint.x = scaleGlassRectangle.x + scaleGlassRectangle.width / 2;      clickPoint.y = scaleGlassRectangle.y + scaleGlassRectangle.height / 2;      var index = -1;        for (var i = 0; i < scaleGlassLines.length; i++) {          var scaleLine = scaleGlassLines[i];            xStart = scaleGlassRectangle.x + scaleLine.xStart - 3;          xEnd = scaleGlassRectangle.x + scaleLine.xStart + 3;          yStart = scaleGlassRectangle.y + scaleLine.yStart;          yEnd = scaleGlassRectangle.y + scaleLine.yEnd;            if (clickPoint.x > xStart && clickPoint.x < xEnd && clickPoint.y < yStart && clickPoint.y > yEnd) {              scaleLine.color = "#f00";              index = scaleLine.index;              break;          }      }        for (var i = 0; i < chartLines.length; i++) {          var line = chartLines[i];          if (line.index == index) {              line.color = "#f00";          } else {              line.color = "#888";          }      }        draw();  }

      鍵盤事件

      因為線段離得比較近,所以使用鼠標(biāo)移動很難精確的選中線段,這里使用鍵盤的w, a, s, d 來進(jìn)行精確移動

     

    document.onkeyup = function (e) {      if (e.key == 'w') {          centerPoint.y = intAdd(centerPoint.y, -0.2);      }      if (e.key == 'a') {          centerPoint.x = intAdd(centerPoint.x, -0.2);      }      if (e.key == 's') {          centerPoint.y = intAdd(centerPoint.y, 0.2);      }      if (e.key == 'd') {          centerPoint.x = intAdd(centerPoint.x, 0.2);      }      draw();  }

    贊(0)
    分享到: 更多 (0)
    網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號