新文章 网摘 文章 随笔 日记

HTML5 - 让Canvas内部元素实现鼠标移入、移出效果(Tooltip提示效果)

文章来源:https://www.hangge.com/blog/cache/detail_1876.html

    Canvas 是一种非保留性的绘图界面,即不会记录过去执行的绘图操作,而是保持最终结果(构成图像的彩色像素)。
    如果想让 Canvas 变得具有交互性,比如用户可以选择、拖动画布上的图形。那么我们必须记录绘制的每一个对象,才能在将来灵活的修改并重绘它们,实现交互。
    在之前的文章中(点击查看)我演示了如何实现通过鼠标点击来选择图形,以及图形的拖动。本文接着介绍如何实现当鼠标移入到一个图形元素上,显示相应 tooltip 提示信息的功能。
 

1,效果图

(1)下面样例中点击“添加圆圈”按钮可以在画布上增加位置、大小、颜色都是随机的圆圈。
(2)点击“清空画布”按钮可以清除画布上所有圆圈。
(3)鼠标移动到任意圆圈上,该圆圈会出现黑色边框,同时在鼠标位置处会显示该圆圈的 tip 提示文本信息(跟随鼠标)。
(4)鼠标移出圆圈,该圆圈的黑色边框消失,同时 tip 提示框也会自动隐藏。
原文:HTML5 - 让Canvas内部元素实现鼠标移入、移出效果(Tooltip提示效果)
 

2,代码说明

(1)为了能够将圆圈对象保存起来,我们定义了一个叫 Circle() 的函数类创建自定义对象。同时要让这个对象能够保持数据,要使用关键字 this 来创建属性。
 
(2)drawCircles() 函数用来根据当前圆圈的集合来填充画布。drawToolTip() 函数用来绘制 toolTip 提示框。每次程序刷新画布时,会先使用 clearRect() 方法清除画布上的所有内容。但不用当心这样会造成画布闪烁,即画布上的圆圈一下子全部消失,然后一下子又重新出现。
因为 Canvas 针对这个问题进行了优化,会在所有绘图逻辑执行完毕后才清除或绘制所有内容,保证最终结果的流畅。
 
(3)我们监听 canvas 的鼠标移动事件(mousemove),当鼠标每次移动时都与所有的圆形进行碰撞检测。即计算鼠标当前位置是否落在某个形状里。对于圆圈而言,只要计算当前点与圆心的直线距离即可。
  • 如果找到符合条件的圆圈,则将其设置为选中,重绘时对该圆圈描黑边。同时再绘制一个提示框(包含提示框背景,以及上面的提示文字)。
  • 如果没找到符合条件的圆圈,则将之前选中的圆圈置为未选中(如果有的话),那么重绘所有圆圈均无黑边。且提示框也不再绘制。
 

3,样例代码

(高亮处表示与 tooltip 相关的代码)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>hangge.com</title>
 
 <style>
     canvas {
       cursor: pointer;
       border: 1px solid black;
     }
 </style>
 <script>
    // 这个方法用来储存每个圆圈对象
    function Circle(x, y, radius, color) {
      this.x = x;
      this.y = y;
      this.radius = radius;
      this.color = color;
      this.isSelected = false;
    }
 
    // 保存画布上所有的圆圈
    var circles = [];
 
    var canvas;
    var context;
 
    window.onload = function() {
      canvas = document.getElementById("canvas");
      context = canvas.getContext("2d");
 
      canvas.onmousemove = onMouseMove;
    };
 
    //“添加圆圈”按钮点击
    function addRandomCircle() {
      // 为圆圈计算一个随机大小和位置
      var radius = randomFromTo(10, 60);
      var x = randomFromTo(0, canvas.width);
      var y = randomFromTo(0, canvas.height);
 
      // 为圆圈计算一个随机颜色
      var colors = ["green""blue""red""yellow""magenta""orange""brown",
                    "purple""pink"];
      var color = colors[randomFromTo(0, 8)];
 
      // 创建一个新圆圈
      var circle = new Circle(x, y, radius, color);
 
      // 把它保存在数组中
      circles.push(circle);
 
      // 重新绘制画布
      drawCircles();
    }
 
    //“清空画布”按钮点击
    function clearCanvas() {
      // 去除所有圆圈
      circles = [];
 
      // 重新绘制画布.
      drawCircles();
    }
 
    //绘制圆圈
    function drawCircles() {
      // 清除画布,准备绘制
      context.clearRect(0, 0, canvas.width, canvas.height);
 
      // 遍历所有圆圈
      for(var i=0; i<circles.length; i++) {
        var circle = circles[i];
 
        // 绘制圆圈
        context.globalAlpha = 0.85;
        context.beginPath();
        context.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2);
        context.fillStyle = circle.color;
        context.strokeStyle = "black";
 
        if (circle.isSelected) {
          context.lineWidth = 5;
        }
        else {
          context.lineWidth = 1;
        }
        context.fill();
        context.stroke();
      }
    }
 
    //绘制tooltip提示文字
    function drawToolTip(txtLoc, x, y) {
        context.save();
        var padding = 3;
        var font = "16px arial";
        context.font = font;
        context.textBaseline = 'bottom';
        context.fillStyle = 'yellow';
 
        //绘制ToolTip背景
        var width = context.measureText(txtLoc).width;
        var height = parseInt(font, 10);
        context.fillRect(x, y-height, width+padding*2, height+padding*2);
 
        //绘制ToolTip文字
        context.fillStyle = '#000';
        context.fillText(txtLoc, x+padding, y+padding);
 
        context.restore();
    }
 
    //当前选中的圆圈
    var previousSelectedCircle;
 
    //鼠标移动事件
    function onMouseMove(e) {
      // 清除之前选择的圆圈
      if (previousSelectedCircle != null) {
        previousSelectedCircle.isSelected = false;
        previousSelectedCircle = null;
      }
 
      // 取得画布上被单击的点
      var clickX = e.pageX - canvas.offsetLeft;
      var clickY = e.pageY - canvas.offsetTop;
 
      // 查找被单击的圆圈
      for(var i=circles.length-1; i>=0; i--) {
        var circle = circles[i];
        //使用勾股定理计算这个点与圆心之间的距离
        var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2)
            + Math.pow(circle.y - clickY, 2))
        // 判断这个点是否在圆圈中
        if (distanceFromCenter <= circle.radius) {
          previousSelectedCircle = circle;
 
          //选择新圆圈
          circle.isSelected = true;
 
          //停止搜索
          break;
        }
      }
 
      //更新显示,重绘圆圈
      drawCircles();
      //如果当前鼠标位置有圆圈,还要显示tip
      if(previousSelectedCircle != null){
        drawToolTip("颜色:" + previousSelectedCircle.color, clickX, clickY);
      }
    }
 
    //在某个范围内生成随机数
    function randomFromTo(from, to) {
      return Math.floor(Math.random() * (to - from + 1) + from);
    }
 </script>
</head>
 
<body>
 
  <canvas id="canvas" width="360" height="300">
  </canvas>
 
  <div>
    <button onclick="addRandomCircle()">添加圆圈</button>
    <button onclick="clearCanvas()">清空画布</button>
  </div>
 
</body>
</html>


原文出自:www.hangge.com  转载请保留原文链接:https://www.hangge.com/blog/cache/detail_1876.html

posted @ 2023-01-17 08:32  岭南春  阅读(1791)  评论(0)    收藏  举报