【HTML5】Canvas 实现放大镜效果
目录
图片放大镜
效果
在线演示 源码
原理
首先选择图片的一块区域,然后将这块区域放大,然后再绘制到原先的图片上,保证两块区域的中心点一致, 如下图所示:
初始化
<canvas id="canvas" width="500" height="500"> </canvas> <img src="/static/imghw/default1.png" data-src="image.png" class="lazy" style="max-width:90%" id="img" alt="【HTML5】Canvas 实现放大镜效果" >
获得 canvas 和 image 对象,这里使用 标签预加载图片, 关于图片预加载可以看这里
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 函数裁剪出一个圆形区域,然后在该区域中绘制放大后的图。一旦裁减了某个区域,以后所有的绘图都会被限制的这个区域里,这里我们使用 save 和 restore 方法清除裁剪区域的影响。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

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

L'exécution du projet H5 nécessite les étapes suivantes: Installation des outils nécessaires tels que le serveur Web, Node.js, les outils de développement, etc. Créez un environnement de développement, créez des dossiers de projet, initialisez les projets et écrivez du code. Démarrez le serveur de développement et exécutez la commande à l'aide de la ligne de commande. Aperçu du projet dans votre navigateur et entrez l'URL du serveur de développement. Publier des projets, optimiser le code, déployer des projets et configurer la configuration du serveur Web.

La production de pages H5 fait référence à la création de pages Web compatibles compatibles multiplateformes à l'aide de technologies telles que HTML5, CSS3 et JavaScript. Son cœur réside dans le code d'analyse du navigateur, la structure de rendu, le style et les fonctions interactives. Les technologies courantes incluent les effets d'animation, la conception réactive et l'interaction des données. Pour éviter les erreurs, les développeurs doivent être débogués; L'optimisation des performances et les meilleures pratiques incluent l'optimisation du format d'image, la réduction des demandes et les spécifications du code, etc. pour améliorer la vitesse de chargement et la qualité du code.

Les étapes pour créer une icône H5 Click comprennent: la préparation d'une image source carrée dans le logiciel d'édition d'image. Ajoutez l'interactivité dans l'éditeur H5 et définissez l'événement Click. Créez un hotspot qui couvre l'icône entière. Définissez l'action des événements de clic, tels que le saut sur la page ou le déclenchement de l'animation. Exporter H5 documents sous forme de fichiers HTML, CSS et JavaScript. Déployez les fichiers exportés vers un site Web ou une autre plate-forme.

H5. La principale différence entre les mini programmes et l'application est: Architecture technique: H5 est basé sur la technologie Web, et les mini-programmes et l'application sont des applications indépendantes. Expérience et fonctions: H5 est légère et facile à utiliser, avec des fonctions limitées; Les mini-programmes sont légers et ont une bonne interactivité; Les applications sont puissantes et ont une expérience fluide. Compatibilité: H5 est compatible multiplateforme, les applets et les applications sont limités par la plate-forme. Coût de développement: H5 a un faible coût de développement, des mini-programmes moyens et une application la plus élevée. Scénarios applicables: H5 convient à l'affichage d'informations, les applets conviennent aux applications légères et les applications conviennent aux fonctions complexes.

L'article traite de la gestion de la confidentialité de l'emplacement des utilisateurs et des autorisations à l'aide de l'API Geolocation, mettant l'accent sur les meilleures pratiques pour demander des autorisations, assurer la sécurité des données et se conformer aux lois sur la confidentialité.

H5 n'est pas un langage de programmation autonome, mais une collection de HTML5, CSS3 et JavaScript pour la création d'applications Web modernes. 1. HTML5 définit la structure et le contenu de la page Web et fournit de nouvelles balises et API. 2. CSS3 contrôle le style et la mise en page, et introduit de nouvelles fonctionnalités telles que l'animation. 3. JavaScript implémente l'interaction dynamique et améliore les fonctions par les opérations DOM et les demandes asynchrones.

H5 (HTML5) convient aux applications légères, telles que les pages de campagne de marketing, les pages d'affichage des produits et les micro-Websites de promotion d'entreprise. Ses avantages résident dans la plateformité multi-plateaux et une riche interactivité, mais ses limites résident dans des interactions et des animations complexes, un accès aux ressources locales et des capacités hors ligne.

<p> La fonction de page suivante peut être créée via HTML. Les étapes incluent: la création d'éléments de conteneur, la division du contenu, l'ajout de liens de navigation, la cachette d'autres pages et l'ajout de scripts. Cette fonctionnalité permet aux utilisateurs de parcourir du contenu segmenté, affichant une seule page à la fois et convient pour afficher de grandes quantités de données ou de contenu. </p>
