-
Notifications
You must be signed in to change notification settings - Fork 0
/
example_for_touch_move.html
209 lines (184 loc) · 8.71 KB
/
example_for_touch_move.html
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
<!doctype html>
<html>
<head>
<style>
body {
margin: 0;
}
/* 最外层容器 */
#content {
/* 阻止页面大小随着SVG移动而变化 */
overflow: hidden;
}
/* 固定Header */
#header {
left: 0;
right: 0;
position: fixed;
height: 50px!important;
background-color: rgb(124, 252, 45);
z-index: 10;
}
/* 容纳需要跟随手势移动的SVG的容器 */
#panel_container {
height: 100vh;
z-index: 5;
background-color: rgb(248, 213, 98);
}
/* 固定Footer */
#footer {
left: 0;
right: 0;
bottom: 0;
position: fixed;
height: 50px!important;
background-color: rgb(124, 252, 45);
z-index: 10;
}
/* 需要跟随手势移动的SVG */
svg {
background-color: rgb(250, 250, 153);
width: 100%;
height: 100%;
}
</style>
<script>
// 需要跟随手势移动的SVG。页面加载后赋值
var svg = null;
// 用户操作后期望的SVG缩放比例
var scale = 1;
// 用户操作后期望的SVG中心点的横向偏移
var posX = 0;
// 用户操作后期望的SVG中心点的纵向偏移
var posY = 0;
// 我们不希望SVG比例过小或偏出屏幕,所以在SVG被移动或缩放到符合用户期望的比例和位置后,还需要让SVG回弹到以下符合我们期望的比例和位置
// 经过修正后的SVG缩放比例
var finalScale = 1;
// 经过修正后的SVG中心点的横向偏移
var finalPosX = 0;
// 经过修正后的SVG中心点的纵向偏移
var finalPosY = 0;
// 上次根据用户操作进行渲染的时间戳。每次执行render()时被设置。用户的操作优先于系统的回弹修正,所以只有当前时间距离该时间戳已经过去了一段时间(200毫秒)后,我们才可以开始对SVG进行回弹修正。详见bounce()
var lastRenderingTime;
// 监听页面加载完成事件。为SVG加点元素以便位置参考
window.addEventListener("load", function() {
svg = document.querySelector("svg");
// 简单加一个小方块
let newRect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
newRect.setAttribute("x", "150");
newRect.setAttribute("y", "150");
newRect.setAttribute("width", "100");
newRect.setAttribute("height", "100");
newRect.setAttribute("fill", "#5cceee");
svg.appendChild(newRect);
});
// 根据用户的操作进行渲染
var render = () => {
// 更新渲染的时间戳
lastRenderingTime = new Date().getTime();
window.requestAnimationFrame(() => {
// 根据新的位置和缩放比例渲染SVG
svg.style.transform = `translate3D(${posX}px, ${posY}px, 0px) scale(${scale})`;
// 如果不想要回弹效果,以下代码可以去掉
// 让系统稍后尝试回弹修正(有必要的话)
setTimeout(bounce, 500);
});
};
// 如果不想要回弹效果,以下bounce()代码可以去掉
// 根据修正值回弹修正SVG
var bounce = () => {
// 用户操作后的缩放和位置没有问题,用户期望与系统期望相同,直接返回
if (scale == finalScale && posX == finalPosX && posY == finalPosY) return;
// 用户可能还在操作中,按优先级规则不进行系统操作,而是等待片刻再尝试
if (new Date().getTime() - lastRenderingTime < 200) {
// 等待500毫秒
setTimeout(bounce, 500);
// 返回
return;
}
// 容纳SVG的容器。结合SVG和容纳SVG的容器的相对位置和大小来计算回弹量
var ref = document.getElementById("panel_container").getBoundingClientRect();
// SVG当前的缩放比例
var lastScale = svg.getBoundingClientRect().width / ref.width;
// SVG当前的中心点横向偏移
var lastPosX = svg.getBoundingClientRect().x + svg.getBoundingClientRect().width / 2 - ref.width / 2;
// SVG当前的中心点纵向偏移
var lastPosY = svg.getBoundingClientRect().y + svg.getBoundingClientRect().height / 2 - ref.height / 2;
// 该次回弹的目标比例。与最终修正值差距过小则直接置为最终修正值
var stepScale = Math.abs(finalScale - lastScale) > 0.1 ? (lastScale + Math.sign(finalScale - lastScale) * 0.1) : finalScale;
// 该次回弹的目标中心点横向偏移。与最终修正值差距过小则直接置为最终修正值
var stepPosX = Math.abs(finalPosX - lastPosX) > 10 ? (lastPosX + (finalPosX - lastPosX) / 10 + Math.sign(finalPosX - lastPosX) * 10) : finalPosX;
// 该次回弹的目标中心点纵向偏移。与最终修正值差距过小则直接置为最终修正值
var stepPosY = Math.abs(finalPosY - lastPosY) > 10 ? (lastPosY + (finalPosY - lastPosY) / 10 + Math.sign(finalPosY - lastPosY) * 10) : finalPosY;
window.requestAnimationFrame(() => {
// 根据目标位置和缩放比例渲染SVG
svg.style.transform = `translate3D(${stepPosX}px, ${stepPosY}px, 0px) scale(${stepScale})`;
});
// 如果已经修正完成则返回
if (stepScale == finalScale && stepPosX == finalPosX && stepPosY == finalPosY) return;
// 继续尝试进行下一次修正
setTimeout(bounce, 500);
};
// 监听触控板手势事件。实际为鼠标滚轮事件
window.addEventListener('wheel', (e) => {
// 容纳SVG的容器。结合SVG和容纳SVG的容器的相对位置和大小来计算修正值
var ref = document.getElementById("panel_container").getBoundingClientRect();
// SVG当前的缩放比例
var lastScale = svg.getBoundingClientRect().width / ref.width;
// SVG当前的中心点横向偏移
var lastPosX = svg.getBoundingClientRect().x + svg.getBoundingClientRect().width / 2 - ref.width / 2;
// SVG当前的中心点纵向偏移
var lastPosY = svg.getBoundingClientRect().y + svg.getBoundingClientRect().height / 2 - ref.height / 2;
if (e.ctrlKey) {
// 缩放事件
// 根据操作确定缩放值。位置不变
finalScale = scale = lastScale - e.deltaY * 0.01;
finalPosX = posX = lastPosX;
finalPosY = posY = lastPosY;
} else {
// 移动事件
// 根据操作确定位置。缩放值不变
finalScale = scale = lastScale;
finalPosX = posX = lastPosX - e.deltaX * 2;
finalPosY = posY = lastPosY - e.deltaY * 2;
}
// 如果不想要回弹效果,以下对finalXXX的赋值可以直接修改为对XXX的赋值
// 不允许SVG过小(缩放值小于1)
if (scale < 1) finalScale = 1;
// 不允许SVG右边界进入屏幕内
var minPosX = ref.width / 2 - ref.width * finalScale / 2;
// 不允许SVG左边界进入屏幕内
var maxPosX = ref.width * finalScale / 2 - ref.width / 2;
// 不允许SVG下边界进入屏幕内
var minPosY = ref.height / 2 - ref.height * finalScale / 2;
// 不允许SVG上边界进入屏幕内
var maxPosY = ref.height * finalScale / 2 - ref.height / 2;
// 根据以上限制值确定系统最终修正值
if (posX < minPosX) finalPosX = minPosX;
if (posX > maxPosX) finalPosX = maxPosX;
if (posY < minPosY) finalPosY = minPosY;
if (posY > maxPosY) finalPosY = maxPosY;
// 根据用户操作进行渲染
render();
});
</script>
</head>
<body>
<!-- 最外层容器 -->
<div id='content'>
<!-- 放置一个固定Header为肉眼观察位移作参考 -->
<div id='header'>
Header
</div>
<!-- 容纳需要跟随手势移动的SVG的容器 -->
<div id='panel_container'>
<!-- 需要跟随手势移动的SVG -->
<svg></svg>
</div>
<!-- 放置一个固定Footer为肉眼观察位移作参考 -->
<div id='footer'>
Footer
</div>
</div>
</body>
</html>