HTML5 Canvas完成变大镜实际效果示例

日期:2021-02-22 类型:科技新闻 

关键词:h5平台,手机端网页,手机端网页模板,免费的h5场景制作平台,h5制作工具

照片变大镜实际效果

线上源代码预览

源代码

基本原理

最先挑选照片的1块地区,随后将这块地区变大,随后再绘图到本来的照片上,确保两块地区的管理中心点1致, 以下图所示:

原始化

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

绘图变大镜地区

剪裁地区

变大镜1般是圆形的,这里大家应用 clip 涵数剪裁出1个圆形地区,随后在该地区中绘图变大后的图。1旦裁掉了某个地区,之后全部的制图都会被限定的这个地区里,这里大家应用 saverestore 方式消除剪裁地区的危害。save 储存当今画布的1次情况,包括 canvas 的左右文特性,比如 stylelineWidth 等,随后会将这个情况压入1个堆栈。restore 用来修复上1次 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 本身做为1副照片,随后取被变大地区的图象,将其绘图到变大镜地区里。

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) {
    ......
}

变换座标

电脑鼠标恶性事件得到座标1般为显示屏的或 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 绘图1些图表或图象,假如两个元素的座标离得较为近,就会给元素的挑选带来1些危害,比如大家画两条线,1个线的座标是(200.5, 400) -> (200.5, 200),另外一个线的座标为 (201.5, 400) -> (201.5, 20),那末这两条线基本上就会重合在1起,以下图所示:

应用图表变大镜的实际效果

线上演试    源代码

基本原理

相近于地形图中的图例,变大镜应用较为精准的图例,以下图所示:

在变大镜座标系统软件中,初始的地区会增大,以下图所示

绘图初始直线

最先建立1个直线目标

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', 当电脑鼠标按下时,检验是不是在变大镜地区,假如在,设定变大镜能够挪动。电脑鼠标挪动时升级变大镜zte中兴点的座标。电脑鼠标松开时,设定变大镜不能以被挪动。

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 = ⑴;

    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变大镜內容请检索脚本制作之家之前的文章内容或再次访问下面的有关文章内容,期待大伙儿之后多多适用脚本制作之家!