亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > HTML5 > 正文

HTML5 Canvas實現放大鏡效果示例

2024-09-05 07:23:20
字體:
來源:轉載
供稿:網友

圖片放大鏡效果

在線源碼預覽

源碼

原理

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

初始化

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

獲得 canvas 和 image 對象,這里使用 <img> 標簽預加載圖片, 關于圖片預加載可以看這里

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

設置相關變量

// 圖片被放大區域的中心點,也是放大鏡的中心點var centerPoint = {};// 圖片被放大區域的半徑var originalRadius = 100;// 圖片被放大區域var originalRectangle = {};// 放大倍數var scale = 2;// 放大后區域var scaleGlassRectangle

畫背景圖片

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

計算圖片被放大的區域的范圍

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

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

繪制放大鏡區域

裁剪區域

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

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

計算放大鏡區域

通過中心點、被放大區域的寬高以及放大倍數,獲得區域的左上角坐標以及區域的寬高。

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 自身作為一副圖片,然后取被放大區域的圖像,將其繪制到放大鏡區域里。

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();

添加鼠標事件

為 canvas 添加鼠標移動事件

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

轉換坐標

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

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

修改鼠標樣式

我們可以通過 css 來修改鼠標樣式

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

圖表放大鏡

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

使用圖表放大鏡的效果

在線演示    源碼

原理

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

在放大鏡坐標系統中,原始的區域會變大,如下圖所示

繪制原始線段

首先創建一個線段對象

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

初始化線段

// 原始線段var chartLines = new Array();// 處于放大鏡中的原始線段var glassLines;// 放大后的線段var scaleGlassLines;// 位于放大鏡中的線段數量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();    }}

計算原始區域和放大鏡區域

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;    // 將值裝換為整數    scaleGlassRectangle.width = parseInt(scaleGlassRectangle.width);    scaleGlassRectangle.height = parseInt(scaleGlassRectangle.height);    scaleGlassRectangle.x = parseInt(scaleGlassRectangle.x);    scaleGlassRectangle.y = parseInt(scaleGlassRectangle.y);}

計算線段在新坐標系統的位置

由原理圖我們知道,放大鏡中使用坐標系的圖例要比原始坐標系更加精確,比如原始坐標系使用 1:100,那么放大鏡坐標系使用 1:10,因此我們需要重新計算線段在放大鏡坐標系中的位置。同時為了簡便,我們將線段的原始坐標進行了轉化,減去原始區域起始的x值和y值,即將原始區域左上角的點看做為(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;}

繪制放大鏡中心點

繪制放大鏡中心的瞄準器

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();}

添加事件

鼠標拖動

鼠標移動到放大鏡上,然后按下鼠標左鍵,可以拖動放大鏡,不按鼠標左鍵或者不在放大鏡區域都不可以拖動放大鏡。
為了實現上面的效果,我們要實現3種事件 mousedown, mousemove, 'mouseup', 當鼠標按下時,檢測是否在放大鏡區域,如果在,設置放大鏡可以移動。鼠標移動時更新放大鏡中興點的坐標。鼠標松開時,設置放大鏡不可以被移動。

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;}

鼠標雙擊

當移動到對應的線段上時,鼠標雙擊可以選擇該線段,將該線段的顏色變為紅色。

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();}

鍵盤事件

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

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();}

** 參考資料 **
HTML5-MagnifyingGlass

到此這篇關于HTML5 Canvas實現放大鏡效果示例的文章就介紹到這了,更多相關HTML5 Canvas放大鏡內容請搜索武林網以前的文章或繼續瀏覽下面的相關文章,希望大家以后多多支持武林網!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
www.久久色.com| 高清欧美性猛交xxxx| 亚洲视频axxx| 亚洲综合最新在线| 日本精品久久久| 亚洲人成网站777色婷婷| 久久久精品国产| 欧美极品美女视频网站在线观看免费| 日日骚久久av| 另类专区欧美制服同性| 久热在线中文字幕色999舞| 国产一区av在线| 日本一区二区在线免费播放| 欧美电影免费观看| 欧美老肥婆性猛交视频| 国产在线一区二区三区| 伊人久久大香线蕉av一区二区| 久久精品91久久久久久再现| 久久久亚洲精选| 国产精品第1页| 久久久久久久激情视频| 亚洲资源在线看| 岛国视频午夜一区免费在线观看| 国产精品人成电影在线观看| 亚洲国产成人久久综合一区| 亚洲精品中文字幕av| 欧美猛交ⅹxxx乱大交视频| 亚洲自拍偷拍色片视频| 全色精品综合影院| 人人做人人澡人人爽欧美| 亚洲伊人成综合成人网| 亚洲最大在线视频| 亚洲视频在线观看免费| 欧美日韩国产精品一区二区三区四区| 亚洲视屏在线播放| 久久高清视频免费| 亚洲免费视频一区二区| 久久精品亚洲精品| 欧美一区二区三区艳史| 九九热精品视频在线播放| 欧美中文在线字幕| 国产精品高清免费在线观看| 亚洲精品电影网在线观看| 欧美日韩一区二区在线播放| 不卡毛片在线看| 欧美日韩国产中文精品字幕自在自线| 成年人精品视频| 亚洲最大福利视频网站| 欧美大码xxxx| 国产欧美日韩中文| 欧美一级视频免费在线观看| 亚洲图片欧洲图片av| 国产精品27p| 最好看的2019的中文字幕视频| 成人精品一区二区三区电影黑人| 久久视频在线播放| 欧美日本啪啪无遮挡网站| 激情久久av一区av二区av三区| 国产欧美在线观看| 亚洲精品久久久久久久久久久久久| 精品人伦一区二区三区蜜桃免费| 国产一区香蕉久久| 亚洲男人天堂古典| 深夜福利91大全| 久久躁日日躁aaaaxxxx| 国产精品999| 精品福利视频导航| 在线日韩av观看| 国产一区二区在线免费| 久久精品人人爽| 欧美视频在线免费看| 91日本在线观看| 国产精品久久久久久搜索| 欧亚精品在线观看| 亚洲国产精品久久精品怡红院| 久久精品91久久香蕉加勒比| 亚洲黄色www| 欧美日韩不卡合集视频| 欧美大尺度在线观看| 成人黄色网免费| 欧美人与性动交a欧美精品| 国产男人精品视频| 免费97视频在线精品国自产拍| 欧美老女人xx| 91中文字幕一区| 国产精品爱久久久久久久| 亚洲欧洲黄色网| 日韩电影免费观看在线| 欧美高清视频在线| 国产suv精品一区二区三区88区| 欧美老女人在线视频| 久久亚洲精品成人| 亚洲视频日韩精品| 国产精品日韩欧美大师| 久久精品国产清自在天天线| 欧美精品电影在线| 久久精品99久久香蕉国产色戒| 精品国产成人av| 中文字幕无线精品亚洲乱码一区| 亚洲自拍欧美色图| 亚洲伊人成综合成人网| 欧美激情videos| 欧美日韩999| 色老头一区二区三区在线观看| 国产成人精品日本亚洲| 亚洲天堂av在线播放| 国产伊人精品在线| 日韩中文在线不卡| 久久视频国产精品免费视频在线| 亚洲精品女av网站| 欧美黑人巨大精品一区二区| 91国产精品电影| 久久久之久亚州精品露出| 国产精自产拍久久久久久蜜| 国产综合在线视频| 欧美性色视频在线| 欧美激情视频网| 青草热久免费精品视频| 亚洲第一男人天堂| 在线电影av不卡网址| 91在线视频精品| 91高清在线免费观看| 日韩国产中文字幕| 日韩av网站在线| 国产综合在线看| 欧美又大粗又爽又黄大片视频| 亚洲国产成人精品久久| 亚洲成av人影院在线观看| 国产成人在线一区二区| 亚洲国产美女久久久久| 国产日韩视频在线观看| 91亚洲午夜在线| 一本色道久久88综合亚洲精品ⅰ| 亚洲国产精久久久久久| 91在线播放国产| 欧美激情国产日韩精品一区18| 性欧美办公室18xxxxhd| 久久中文字幕在线视频| 国产精品美女主播| 国产免费一区视频观看免费| 国产亚洲欧洲在线| 久久久av亚洲男天堂| 亚洲欧美国产精品久久久久久久| 在线播放国产一区中文字幕剧情欧美| 亚洲香蕉在线观看| 久久精品视频免费播放| 国产日韩欧美另类| 91美女片黄在线观看游戏| 亚洲人在线视频| 欧美老女人性生活| xxxxx91麻豆| 91色琪琪电影亚洲精品久久| 精品亚洲aⅴ在线观看| 91精品视频观看| 日韩毛片在线看| 国产精品视频白浆免费视频| 亚洲视频777| 亚洲自拍中文字幕| 91精品综合视频| 日本成熟性欧美| 91av在线播放视频| 久久久久这里只有精品| 欧美性极品少妇精品网站| 国产99视频在线观看|