Canvas 2D Web 应用/静态按钮
本章讨论了使用 cui2d 实现按钮的最基本方法。这当然不是实现按钮的唯一方法,但它非常灵活,定义按钮外观和功能的代码只是一个简单的 if
语句,它检查用户事件是否发生在按钮区域,并指定如何对这些事件做出反应。在本章中,按钮的外观是静态的;根据用户事件(例如,鼠标悬停)改变其外观的按钮将在关于 响应式按钮 的章节中讨论。
本章的示例显示了三个分别标记为“红色”、“绿色”和“蓝色”的按钮,以及一个颜色补丁,其颜色根据点击的按钮而变化。按钮使用位图图像渲染,允许任意按钮设计。该示例可 在线 获得,并且还可 在线 获得可在移动设备上下载的版本。如果你想在本地计算机上试用该示例,你还需要将文件 cui2d.js
和图像 selected.png
下载到与 HTML 文件相同的目录中。
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no">
<script>
function init() {
// get image
imageFocusedButton.src = "selected.png";
imageFocusedButton.onload = cuiRepaint;
// deactivate single-finger dragging for myPage
myPage.interactionBits = cuiConstants.isTransformableWithTwoFingers;
// set defaults for all pages
cuiBackgroundFillStyle = "#000000";
cuiDefaultFont = "bold 20px Helvetica, sans-serif";
cuiDefaultFillStyle = "#FFFFFF";
// initialize cui2d and start with myPage
cuiInit(myPage);
}
// create an image for the button
var imageFocusedButton = new Image();
// create a color
var myColor = "#000000";
// create a new page of size 400x300 and attach myPageProcess
var myPage = new cuiPage(400, 300, myPageProcess);
// a function to repaint the canvas and return false (if null == event)
// or to process user events (if null != event) and return true
// if the event has been processed
function myPageProcess(event) {
// draw and react to buttons
if (cuiIsInsideRectangle(event, 50, 50, 80, 50, "red", imageFocusedButton)) {
if ("mouseup" == event.type || "touchend" == event.type) {
myColor = "#FF0000";
cuiRepaint();
return true;
}
}
if (cuiIsInsideRectangle(event, 150, 50, 80, 50, "green", imageFocusedButton)) {
if ("mouseup" == event.type || "touchend" == event.type) {
myColor = "#00FF00";
cuiRepaint();
return true;
}
}
if (cuiIsInsideRectangle(event, 250, 50, 80, 50, "blue", imageFocusedButton)) {
if ("mouseup" == event.type || "touchend" == event.type) {
myColor = "#0000FF";
cuiRepaint();
return true;
}
}
// click on background?
if (null != event) {
if ("mouseup" == event.type || "touchend" == event.type) {
myColor = "#000000";
cuiRepaint();
return true;
}
}
// repaint this page?
if (null == event) {
// draw color box
cuiContext.fillStyle = myColor;
cuiContext.fillRect(150, 150, 80, 80);
// background
cuiContext.fillStyle = "#404040";
cuiContext.fillRect(0, 0, this.width, this.height);
}
return false; // event has not been processed
}
</script>
</head>
<body bgcolor="#000000" onload="init()"
style="-webkit-user-drag:none; -webkit-user-select:none; ">
<span style="color:white;">A canvas element cannot be displayed.</span>
</body>
</html>
本讨论假设您熟悉第 框架入门 章中讨论的代码示例。
该示例使用位图图像绘制按钮。该图像分配给全局变量 imageFocusedButton
// create an image for the button
var imageFocusedButton = new Image();
然后在 init()
函数中指定图像文件
// get image
imageFocusedButton.src = "selected.png";
imageFocusedButton.onload = cuiRepaint;
通过将 onload
设置为 cuiRepaint
,我们可以确保在图像完全加载之前,如果画布已被渲染,则重新绘制画布。
该示例定义了一个全局变量 myColor
来存储用户选择的颜色
// create a color
var myColor = "#000000";
由于该示例使用背景上的点击将 myColor
设置为黑色,因此这些“单指”事件不应由页面处理。因此,该示例通过仅允许此页面的双指手势来禁用单指拖动
// deactivate single-finger dragging for myPage
myPage.interactionBits = cuiConstants.isTransformableWithTwoFingers;
为了重新绘制按钮并处理按钮上的点击,该示例使用了三次对 cuiIsInsideRectangle()
的调用
// draw and react to buttons
if (cuiIsInsideRectangle(event, 50, 50, 80, 50, "red", imageFocusedButton)) {
if ("mouseup" == event.type || "touchend" == event.type) {
myColor = "#FF0000";
cuiRepaint();
return true;
}
}
if (cuiIsInsideRectangle(event, 150, 50, 80, 50, "green", imageFocusedButton)) {
if ("mouseup" == event.type || "touchend" == event.type) {
myColor = "#00FF00";
cuiRepaint();
return true;
}
}
if (cuiIsInsideRectangle(event, 250, 50, 80, 50, "blue", imageFocusedButton)) {
if ("mouseup" == event.type || "touchend" == event.type) {
myColor = "#0000FF";
cuiRepaint();
return true;
}
}
cuiIsInsideRectangle()
的定义将在下面讨论。这里,重要的是它与处理函数的工作方式类似
- 如果
event
为null
,cuiIsInsideRectangle()
会在指定的矩形中写入一个字符串("red"
、"green"
或"blue"
),然后在其下方绘制imageFocusedButton
。 - 如果
event
不为null
,则它会检查此用户事件是否在指定的矩形内,如果在矩形内,则返回true
。在这种情况下,将检查事件的类型,在mouseup
和touchend
事件的情况下,myColor
将更改为某种颜色(取决于按钮),并使用cuiRepaint()
请求重新绘制以确保新颜色用于绘制。此外,该函数将返回true
以指示事件已处理。
以下代码检查其他地方是否发生了 mouseup
或 touchend
,在这种情况下,它将 myColor
设置为黑色
// click on background?
if (null != event) {
if ("mouseup" == event.type || "touchend" == event.type) {
myColor = "#000000";
cuiRepaint();
return true;
}
}
最后,该函数检查 event
是否为 null
,如果是,则它使用颜色 myColor
和灰色背景重新绘制一个正方形矩形
// repaint this page?
if (null == event) {
// draw color box
cuiContext.fillStyle = myColor;
cuiContext.fillRect(150, 150, 80, 80);
// background
cuiContext.fillStyle = "#404040";
cuiContext.fillRect(0, 0, this.width, this.height);
}
然后,该函数返回 false
以指示事件未处理。
当你尝试这个示例时,你可能会意识到它感觉非常静态,即使你可以通过点击按钮和背景来改变颜色。第 响应式按钮 章中的示例感觉更加动态,因为按钮的外观会对用户事件做出反应。
函数 cuiIsInsideRectangle()
在 cui2d.js
中定义
/**
* Either determine whether the event's position is inside a rectangle (if event != null)
* or draw an image in the rectangle with a text string on top of it (if event == null).
*/
function cuiIsInsideRectangle(event, x, y, width, height, text, image) {
if (null == event) { // draw button
if (null != text) {
cuiContext.fillText(text, x + width / 2, y + height / 2);
}
if (null != image) {
cuiContext.drawImage(image, x, y, width, height);
}
return false;
}
else { // if (null != event)
if (event.eventX >= x && event.eventX < x + width &&
event.eventY >= y && event.eventY < y + height) {
return true;
}
return false;
}
}
实现非常简单:如果 event
为 null
,则除非 text
为 null
,否则 text
将写入矩形的中心。同样,除非 image
为 null
,否则 image
将绘制到矩形中。另一方面(如果 event
不为 null
),该函数会检查事件中的坐标 eventX
和 eventY
是否在矩形内,并返回结果。
请注意,eventX
和 eventY
是 cui2d 特有的:这些坐标位于页面的坐标系中,这与 HTML 使用的任何坐标系都不同,并且如果用户使用双指手势变换页面,它也会发生变化。