Canvas如何实现拾取文本?

拾取文本的实现

判断规则:

文本绘制的结果表现为一个矩形区域,因此,在判断点与文本是否相交时,我们可以采用与矩形相同的判断方法。值得注意的是,在绘制文本的过程中,水平对齐方式垂直对齐方式对文本的最终位置有着显著的影响。为了准确地计算和确定文本的位置,我们可以使用以下代码来计算绘制文本时矩形的位置和大小:

这样,我们就能够基于矩形的位置和大小,进一步判断点与文本是否相交,从而实现更精确的点与文本的交互处理。

示例效果与源代码:

运行效果

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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
<!DOCTYPE html>
<html>

<head>
<title>点图查询-几何法</title>
<meta charset="UTF-8">
<!-- frame所需脚本和样式 -->
<script type="text/javascript" src="/examples/script/lib/jquery-1.11.2.min.js"></script>
<link type="text/css" rel="stylesheet" href="/examples/script/bootstrap-3.3.5/css/bootstrap.min.css">
<script src="/examples/graph/js/helper.js"></script>
</head>

<body style="overflow: hidden; margin:10px;">
<div id="graphWrapper" style="width:850px; height:500px; border:solid 1px #CCC;"></div>
<div style="margin:10px; text-align: left;">
<div class="checkbox" style="font-size: 16px;">
<label style="margin-right:20px"><input id="chkPoint" type="checkbox"></label>
<label style="margin-right:20px"><input id="chkRect" type="checkbox">矩形</label>
<label style="margin-right:20px"><input id="chkPolyline" type="checkbox">线</label>
<label style="margin-right:20px"><input id="chkPolygon" type="checkbox">多边形</label>
<label style="margin-right:20px"><input id="chkCircle" type="checkbox">圆形</label>
<label style="margin-right:20px"><input id="chkEllipse" type="checkbox">椭圆</label>
<label style="margin-right:20px"><input id="chkText" type="checkbox">文字</label>
</div>
</div>
</body>
<script type="module">
import {
Graph, Layer, VectorSource, debug, Color, MathUtil, Collide, circle2LineRing, getStarLineRing,
GGeometryType, Rect, Point, Circle, Ellipse, Text, Polyline, Polygon,
} from "/examples/src/index.js";

// graph对象
let graph = new Graph({
"target": "graphWrapper"
});

// 网格水印层
let debugLayer = debug.generateGrid(Object.assign({ "interval": 10, "graph": graph }, graph.getSize()));
debugLayer.getSource().add(new Text({
"text": "按点拾取(几何法)Demo",
"x": graph.getSize().width / 2,
"y": graph.getSize().height / 2,
"vectorSize": false,
"style": { "lineWidth": 4, "fillStyle": 0, "fillColor": "#D0D0D0", "fontSize": 30, "fontName": "黑体", "textAlign": "center", "textBaseline": "middle" }
}));

// 新建绘图图层
let layer = graph.addLayer();
// 浮动层
let overLayer = graph.addOverLayer();

// pageload
$(document).ready(function () {

$("#hitGraph").append(graph.getRenderer().getHitImage());

graph.getRenderObject().on('mousemove', function (e) {
let point = [e.offsetX, e.offsetY];
let coord = graph.getCoordinateFromPixel(point, true);

// 清空浮动层数据
overLayer.getSource().clearData();

// 碰撞检测
_collideCheck(coord);

// 鼠标位置点
overLayer.getSource().add(new Point({
"x": coord[0],
"y": coord[1],
"size": -5,
"style": { "fillColor": "blue", "fillStyle": 1, "color": "none" }
}));

// 图形重绘
graph.renderLayer(overLayer);
});

// 逐一与数据层中的对象进行碰撞检测
function _collideCheck(coord) {
let datas = layer.getSource().getData();
for (let i = 0, len = datas.length; i < len; i++) {
if (datas[i].contain([coord[0], coord[1]])) {
let clone = datas[i].clone();
clone.setStyle({ "fillColor": "#FF2020", "color": "#FF2020", "lineWidth":4 });
overLayer.getSource().add(clone);
return true;
}
}
return false;
}

// 复选框状态事件:清空或随机生成对象
$("#chkPoint").on("change", function () {
if ($(this).prop("checked")) {
for (let i = 0; i < MathUtil.getRandomNum(6, 10); i++) {
layer.getSource().add(new Point({
"x": MathUtil.getRandomNum(50, 800),
"y": MathUtil.getRandomNum(50, 450),
"size": MathUtil.getRandomNum(10, 20),
"style": { "fillColor": "#FFDFDF", "fillStyle": 1, "lineWidth": 1, "color": "#FFA5E8" }
}));
}
} else {
layer.getSource().clearTypeData(GGeometryType.POINT);
}
graph.render();
});

$("#chkRect").on("change", function () {
if ($(this).prop("checked")) {
for (let i = 0; i < MathUtil.getRandomNum(6, 10); i++) {
layer.getSource().add(new Rect({
"x": MathUtil.getRandomNum(50, 800),
"y": MathUtil.getRandomNum(50, 450),
"width": MathUtil.getRandomNum(40, 70),
"height": MathUtil.getRandomNum(20, 40),
"style": { "fillColor": "#FFDFDF", "fillStyle": 1, "lineWidth": 1, "color": "#FFA5E8" }
}));
}
} else {
layer.getSource().clearTypeData(GGeometryType.RECT);
}
graph.render();
});

$("#chkCircle").on("change", function () {
if ($(this).prop("checked")) {
for (let i = 0; i < MathUtil.getRandomNum(6, 10); i++) {
layer.getSource().add(new Circle({
"x": MathUtil.getRandomNum(50, 800),
"y": MathUtil.getRandomNum(50, 450),
"radius": MathUtil.getRandomNum(20, 40),
"style": { "fillColor": "#DFFFBF", "fillStyle": 1, "lineWidth": 1, "color": "#FFA5E8" }
}));
}
} else {
layer.getSource().clearTypeData(GGeometryType.CIRCLE);
}
graph.render();
});

$("#chkText").on("change", function () {
if ($(this).prop("checked")) {
for (let i = 0; i < MathUtil.getRandomNum(6, 10); i++) {
layer.getSource().add(new Text({
"x": MathUtil.getRandomNum(50, 800),
"y": MathUtil.getRandomNum(50, 450),
"text": "碰撞检测文本",
"style": { "fontSize": 24, "fontName": "黑体", "fillColor": "#0000FF", }
}));
}
} else {
layer.getSource().clearTypeData(GGeometryType.TEXT);
}
graph.render();
});

$("#chkEllipse").on("change", function () {
if ($(this).prop("checked")) {
for (let i = 0; i < MathUtil.getRandomNum(6, 10); i++) {
layer.getSource().add(new Ellipse({
"x": MathUtil.getRandomNum(50, 800),
"y": MathUtil.getRandomNum(50, 450),
"radiusX": MathUtil.getRandomNum(20, 40),
"radiusY": MathUtil.getRandomNum(20, 20),
"style": { "fillColor": "#9FFFFF", "fillStyle": 1, "lineWidth": 1, "color": "#FFA5E8" }
}));
}
} else {
layer.getSource().clearTypeData(GGeometryType.ELLIPSE);
}
graph.render();
});

$("#chkPolyline").on("change", function () {
if ($(this).prop("checked")) {
for (let i = 0; i < MathUtil.getRandomNum(6, 10); i++) {
let [x, y] = [MathUtil.getRandomNum(50, 620), MathUtil.getRandomNum(50, 400)];
layer.getSource().add(new Polyline({
"coords": [[x, y], [x + MathUtil.getRandomNum(10, 300), y + MathUtil.getRandomNum(-100, 100)]],
"style": { "lineWidth": 4, "color": "#00957D" }
}));
}
} else {
layer.getSource().clearTypeData(GGeometryType.POLYLINE);
}
graph.render();
});

$("#chkPolygon").on("change", function () {
if ($(this).prop("checked")) {
for (let i = 0; i < MathUtil.getRandomNum(3, 5); i++) {
let center = [MathUtil.getRandomNum(150, 620), MathUtil.getRandomNum(50, 400)];
let sideNum = MathUtil.getRandomNum(3, 8);
let radius = MathUtil.getRandomNum(20, 40);
layer.getSource().add(new Polygon({
"coords": circle2LineRing(center, radius, sideNum),
"style": { "fillColor": "#E5FFF5", "fillStyle": 1, "lineWidth": 1, "color": "#FF9F9F" }
}));

center = [MathUtil.getRandomNum(150, 620), MathUtil.getRandomNum(50, 400)];
layer.getSource().add(new Polygon({
"coords": getStarLineRing(center, radius, null, sideNum >= 6 ? sideNum - 3 : sideNum),
"style": { "fillColor": "#E5FFF5", "fillStyle": 1, "lineWidth": 1, "color": "#FF9F9F" }
}));
}
} else {
layer.getSource().clearTypeData(GGeometryType.POLYGON);
}
graph.render();
});
})

</script>

</html>

尝试一下 »