HTML5 程序员参考(五)
八、HTML5 API 参考
本章为所有新的 HTML5 JavaScript APIs 提供了详细的参考。有关这些 API 的详细讨论,包括示例和发布时的支持级别,请参见第三章。
服务器发送的事件
服务器发送的事件 API 允许 HTML5 客户端订阅服务器发布的事件服务。然后,服务器可以将事件传输到 HTML5 客户端。
服务器发送事件的 API 是全局 JavaScript 范围内的一个EventSource构造函数。EventSource对象实现了EventTarget接口,类似于 DOM 元素(因此事件可以在其上发布,事件处理程序可以在其上注册)。当一个新的EventSource被实例化时,一个事件服务的 URL 被指定。这将指示浏览器建立到指定 URL 的连接,并开始定期轮询新事件。当接收到一个事件时,EventSource对象将发布一个包含被传输数据的事件。
服务器可以通过使用text/event-stream MIME 类型提供对轮询查询的标准 HTTP 响应,向服务发布事件(如果不使用该 MIME 类型,与服务相关联的EventSource对象将发布一个错误事件)。
EventSource构造函数的 JavaScript API 是:
constructor EventSource(DOMString url)
interface EventSource implements EventTarget: {
readonly DOMString url;
readonly unsigned short readyState;
EventHandler onopen;
EventHandler onmessage;
EventHandler onerror;
void close();
}
语法
var myEventSource = new EventSource('http://www.example.com:8030/event-stream/');
EventSource构造函数接受一个有效 URL 的单个参数,表示一个事件服务。生成的接口具有以下属性:
url:服务的 URL。readyState:接口当前的就绪状态,以整数表示;- 0:正在连接到服务。
- 1:连接到服务并主动侦听事件。
- 2: Closed(在调用了
close方法之后,或者在连接中发生了致命错误)。
onopen:open事件接口。onmessage:message事件接口。onerror:error事件接口。close():close法。调用此方法将关闭与服务的连接。
清单 8-1 展示了一个使用EventSource构造函数的基本例子(注意,你需要从服务器上运行这个例子,而不是直接把它加载到浏览器中)。
清单 8-1 。使用EventSource构造函数
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
</head>
<body>
<h1>Server-sent Events Reference</h1>
<script>
/**
* Handles message events published by the EventSource.
* @param {EventSourceEvent} event
*/
function handleMessage(event) {
// Handle message.
console.log('A message was sent from the server: ', event.data);
}
/**
* Handles error events published by the EventSource.
* @param {EventSourceEvent} event
*/
function handleError(event) {
// Handle an error.
console.error('An error happened on the EventSource: ', event.data);
}
/**
* Handles an open event published by the EventSource.
* @param {EventSourceEvent} event
*/
function handleOpen(event) {
// Handle the open event.
console.log('The connection is now open.');
}
// Create a new connection to the server.
var targetUrl = 'http://www.service.com/my-event-service';
var myEventSource = new EventSource(targetUrl);
// Attach event handlers. Here we are using the addEventListener method.
// You could also directly attach the event handlers using the event interfaces,
// e.g. myEventSource.onmessage = handleMessage.
myEventSource.addEventListener('message', handleMessage);
myEventSource.addEventListener('error', handleError);
myEventSource.addEventListener('open', handleOpen);
</script>
</body>
</html>
从服务器发送的事件采用简单 HTTP 响应的形式,以文本/事件流 MIME 类型发送。事件由多行key : value对组成,并以双换行结束。有效密钥如下:
data:指定要发送给客户端的一行任意数据,客户端将接收它作为event对象的数据属性。用双换行('\n\n')终止data值表示特定事件的结束。在一个事件中允许多个data值;只需用单行换行(\n’)结束每一个,用双行换行结束最后一个。event:指定与此服务器发送的事件相关联的任意事件类型。这将导致从关联的EventTarget对象调度同名的事件,从而允许从服务器触发open、message和error之外的任意事件。如果未指定事件类型,该事件将仅触发EventTarget上的message事件。id:指定与事件序列关联的任意 ID。在事件流上设置一个 ID 使浏览器能够跟踪最后触发的事件,如果连接断开,它将向服务器发送一个last-event-IDHTTP 头。retry:指定浏览器为下一个事件重新查询服务器之前的毫秒数。默认情况下,该值设置为 3000(三秒)。这使得服务器资源能够抑制浏览器查询并防止自己被淹没。
任何文本都可以作为服务器发送的事件进行传输:HTML、CSS、XML、JSON 等等。一个响应可以包含多个事件,一个给定的事件可以包含多个数据属性。例如:
event: watch\n
data: {\n
data: "type":"flash flood",\n
data: "counties":"['Jefferson', 'Arapahoe', 'Douglas', 'Broomfield']",\n
data: "from":"12:30 pm June 12, 2015",\n
data: "to":"7:00 am June 13, 2015",\n
data: "details":"The National Weather Service has issued a flash flood watch."\n
data: }\n
event: warning\n
data: {\n
data: "type":"severe thunderstorm",\n
data: "counties":"['Jefferson']",\n
data: "from":"12:30 pm June 12, 2015",\n
data: "to":"1:00 pm June 12, 2015",\n
data: "details":"The National Weather Service has issued a severe thunderstorm warning."\n
data: }\n\n
这个服务器发送的事件将触发相关联的EventTarget对象上的watch事件和warning事件。watch事件的数据将是 JSON 格式的文本:
{
"type":"flash flood",
"counties":"['Jefferson', 'Arapahoe', 'Douglas', 'Broomfield']",
"from":"12:30 pm June 12, 2015",
"to":"7:00 am June 13, 2015",
"details":"The National Weather Service has issued a flash flood watch."\n
}
warning事件的数据将是 JSON 格式的文本:
{
"type":" severe thunderstorm ",
"counties":"['Jefferson']",
"from":"12:30 pm June 12, 2015",
"to":"1:00 pm June 12, 2015",
"details":" The National Weather Service has issued a severe thunderstorm warning."\n
}
表 8-1。服务器发送事件的标准
|
规格
|
状态
|
统一资源定位器
|
| --- | --- | --- |
| 万维网路联盟(World Wide Web Consortiumˌ简称 W3C) | 起草 | http://dev.w3.org/html5/eventsource/ |
| WHATWG | 生活标准 | www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#server-sent-events |
WebSockets
WebSockets API 提供了一种通过维护网络连接在客户端和服务器之间进行全双工通信的方式。
WebSockets 的 API 是全局 JavaScript 范围内的一个WebSocket构造函数。WebSocket对象实现了EventSource接口,类似于 DOM 元素(这意味着可以在其上调度事件,并在其上注册事件处理程序)。构造函数需要一个 URL(其协议必须是ws://或wss://),还可以带一个可选的协议参数。协议是一个字符串或字符串数组,每个字符串代表一个协议的名称。
当一个新的WebSocket被实例化时,客户端立即向服务器发送一个标准的 HTTP 1.1 GET请求,然后服务器将连接从 HTTP 升级到 WebSocket 网络协议。然后,连接就可以发送和接收数据了。
Strings、Blobs、ArrayBuffers都可以通过插座传输。来自服务器的通信在EventTarget接口上调度事件。与服务器的通信是通过WebSocket对象的send方法完成的。
API 的定义是:
constructor WebSocket(DOMString url, optional (DOMString or DOMString[]) protocols)
interface WebSocket implements EventTarget {
readonly DOMString url;
readonly unsigned short readyState;
readonly unsigned long bufferedAmount;
EventHandler onopen;
EventHandler onerror;
EventHandler onclose;
readonly DOMString extensions;
readonly DOMString protocol;
void close(optional unsigned short code, optional USVString reason);
EventHandler onmessage;
BinaryType binaryType;
void send(USVString|Blob|ArrayBuffer data);
};
语法
// Create a web socket without specifying protocols.
var myWebSocket = new WebSocket('ws://www.example.com/');
// Create a web socket and specify one or more protocols.
var myChatWebSocket = new WebSocket('ws://www.example.com/', chat');
var myWebSocket = new WebSocket('ws://www.example.com/', ['chat', 'json']);
接口的属性是:
url:服务的 URL,在构造WebSocket对象时设置。readyState:表示连接的通信状态的整数值;- 0:客户端仍在连接到服务的过程中。
- 1:连接已经打开,可以使用了。
- 2:连接正在关闭。
- 3:连接关闭,不再活动。
bufferedAmount:等待发送回服务器但尚未发送的字节数。onopen:开放事件接口。onerror:错误事件界面。onclose:关闭事件界面。onmessage:消息事件接口。extensions:服务器使用的任何文件扩展名的名称(如 zip)protocol:正在使用的协议名称。binaryType:正在传输什么类型的数据(如'blob'或'arraybuffer')。send:方法send,用于将数据传回服务器。接受一个参数,即要发送的数据。close:关闭连接的close方法。可以采用两个可选参数,这两个参数通常由使用的协议定义:code:可选数字,代表关闭代码。reason:包含关闭连接原因的字符串。
清单 8-2 展示了一个 WebSocket 的简单实现,包括存根事件处理程序(注意,你需要从服务器上运行这个例子)。
清单 8-2 。使用WebSocket构造函数
<!DOCTYPE HTML>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
</head>
<body>
<h1>Web Sockets Reference</h1>
<script>
// Create a new web socket connection.
var socketUrl = 'ws://www.fgjkjk4994sdjk.com/';
var validProtocols = ['chat', 'json'];
var myWebSocket = new WebSocket(socketUrl, validProtocols);
/**
* Handles an error event on the web socket object.
*/
function handleError() {
console.log('An error occurred on the web socket.');
}
/**
* Handles a close event on the web socket object.
* @param {CloseEvent} event The close event object.
*/
function handleClose(event) {
console.log('The web socket connection was closed because ', event.reason);
}
/**
* Handles an open event on the web socket object.
* @param {OpenEvent} event The open event object.
*/
function handleOpen(event) {
console.log('The web socket connection is open.');
}
/**
* Handles a message event on the web socket object.
* @param {MessageEvent} event The message event object.
*/
function handleMessage(event) {
console.log('A message event has been sent.');
// The event object contains the data that was transmitted from the server.
// That data is encoded either using the chat protocol or the json protocol,
// so we need to deterine which protocol is being used.
if (myWebSocket.protocol === validProtocols[0]) {
console.log('The chat protocol is active.');
console.log('The data the server transmitted is: ', event.data);
// etc...
} else {
console.log('The json protocol is active.');
console.log('The data the server transmitted is: ', event.data);
// etc...
}
}
// Register the event handlers on the web socket.
myWebSocket.addEventListener('error', handleError);
myWebSocket.addEventListener('close', handleClose);
myWebSocket.addEventListener('open', handleOpen);
myWebSocket.addEventListener('message', handleMessage);
</script>
</body>
</html>
提示从头开始构建 WebSocket 服务器是一项复杂的任务。但是,您可以在项目中使用几个开源的 web socket 服务器。如果您想从头开始构建一个,请参阅 WebSocket 协议 RFC 中的第 4、5 和 6 节。
表 8-2。WebSockets 标准
|
规格
|
状态
|
统一资源定位器
|
| --- | --- | --- |
| 万维网路联盟(World Wide Web Consortiumˌ简称 W3C) | 候选人推荐 | www.w3.org/TR/websockets/ |
| WHATWG | 生活标准 | https://html.spec.whatwg.org/multipage/comms.html#network |
| 请求评论 | 完成 | https://tools.ietf.org/html/rfc6455 |
跨文档信息/网络信息
浏览器将允许您在 iframes 中打开来自不同来源的文档,但是如果来自一个来源的脚本试图与来自另一个来源的内容交互,浏览器将抛出一个错误。跨文档消息传递 API(也称为 Web 消息传递)为一个框架中来自一个来源的脚本与另一个框架中来自另一个来源的脚本之间的通信定义了一种安全的方式。这允许来自多个来源的脚本更安全地相互交互。
跨文档消息传递规范在window对象上定义了一个新方法和一个新事件。新方法是postMessage,它有三个参数:
message:您想要从当前上下文传输到目标上下文的消息。使用结构化克隆算法对消息进行序列化,除非您指定应该使用transfer参数来传输对象。origin:您期望目标上下文中的资源具有的来源。如果目标上下文中的资源没有指定的来源,该方法将不起作用。transfer:作为消息一部分的对象数组,这些对象的所有权应该转移到新的上下文中。转移所有权意味着对象将被绑定到目标上下文的源。转移所有权仅限于ArrayBuffer和MessagePort对象。
注意结构化克隆算法被定义为 HTML5 规范的一部分。可以在
www.w3.org/TR/html5/infrastructure.html#safe-passing-of-structured-data看。基本上,这个算法允许你从一个上下文传输任何东西到另一个上下文。例外情况是函数、DOM 元素和Error对象,如果您试图传输它们,它们将抛出一个DATA_CLONE_ERROR。
新事件是message事件,当使用postMessage方法传输消息时,该事件在window对象上被调度。产生的事件对象将有两个重要的属性:
data:该属性将包含从其他上下文发送的消息。source:该属性将包含发送上下文的来源。您应该始终仔细检查消息来源的来源,以防止意外捕获和处理来自意外(可能是恶意)来源的事件。
语法
var targetIframe = document.getElementById('my-iframe');
targetIframe.contentWindow.postMessage('hello world', 'apress.com');
window.addEventListener('message', function(event) {
if (event.source === 'apress.com') {
console.log('A message was received: ', event.data);
}
});
为了演示如何使用 API,您需要两个来自不同来源的页面:一个宿主页面和一个目标页面。主页面将包含一个 iframe 来加载目标页面。宿主页面将向目标页面分派事件,目标页面将侦听消息事件并警告其内容。清单 8-3 是主页面。
清单 8-3 。主页
<!DOCTYPE HTML>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
</head>
<body>
<h1>Cross-Domain Messaging</h1>
<iframe id="target-iframe" src="target-page.html"></iframe>
<p><button id="clickme">Click to send a message to the iframe.</button></p>
<script>
// Create some objects to transfer.
var testBlob = new Blob(['some data']);
var testBuffer = new ArrayBuffer(100);
var testBuffer2 = new ArrayBuffer(8);
// To transfer multiple objects, we need to wrap them in a single carrier. The
// names of the properties don't matter, they're just serving as a place to
// store references to the buffer objects.
var transferObject = {
buffer1: testBuffer,
buffer2: testBuffer2
};
var targetFrame = document.getElementById('target-iframe');
// Reference to the button.
var clickme = document.getElementById("clickme");
// Add a click event handler to the button.
clickme.addEventListener("click", function() {
// Send a simple text string to the target frame.
targetFrame.contentWindow.postMessage('hello world', '*');
// Send a Blob to the target frame.
targetFrame.contentWindow.postMessage(testBlob, '*');
// Transfer multiple array buffers to the target frame.
targetFrame.contentWindow.postMessage(transferObject, '*',
[transferObject.buffer1, transferObject.buffer2]);
});
</script>
</body>
</html>
注意,iframe 元素的src被设置为从相同的上下文中加载目标页面。如果您可以访问不同的域(或者甚至是运行在不同端口上的同一个域中的另一个 web 服务器),您可以从那里提供目标页面,从而充分证明 API 允许跨源发送消息。
清单 8-4 中的包含了目标页面。
清单 8-4 。目标页面
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
</head>
<body>
<h1>Target iframe</h1>
<script>
/**
* Handles a message event on the window object.
* @param {MessageEvent} event A message event object.
*/
function handleMessage(event) {
// Create a string for alerting.
var strAlert = "Target iframe:\n";
if (event.data.buffer1) {
// The two buffers have been transferred.
strAlert += event.data.buffer1 + '\n';
strAlert += event.data.buffer2 + '\n';
} else {
// Just alert the data.
strAlert += event.data;
}
alert(strAlert);
}
// Register the event handler.
window.addEventListener("message", handleMessage, false);
</script>
</body>
</html>
若要运行该示例,请单击按钮。宿主页面将向目标页面发送三条消息,从而产生三个警报。
表 8-3。跨文档消息传递的标准
|
规格
|
状态
|
统一资源定位器
|
| --- | --- | --- |
| 万维网路联盟(World Wide Web Consortiumˌ简称 W3C) | 候选人推荐 | www.w3.org/TR/webmessaging/ |
| WHATWG | 生活标准 | www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#crossDocumentMessages |
网络存储
新的 Web 存储 API 指定了一种在客户端存储信息的新方法。在 Web 存储出现之前,在客户端存储信息的标准方式是使用 HTTP cookies,这种方式既麻烦又不方便。网络存储提供了一种更易于使用的存储功能。
Web 存储在全局上下文中定义了两个新的接口对象:sessionStorage和localStorage。sessionStorage界面用于存储单个浏览会话的数据。当用户关闭浏览器时,数据将被自动删除。localStorage接口用于跨会话存储数据。即使用户关闭浏览器,存储在 localStorage 中的数据也将持续存在。
注意所有的浏览器都实现了某种形式的“隐私浏览”使用此功能时,当用户结束会话时,
localStorage数据被删除。此外,许多浏览器现在都有在浏览器关闭时自动清除localStorage的功能,即使是常规会话。您的应用不应该假设存储在localStorage中的任何数据总是可用的,并且应该在预期的数据不存在时做出适当的响应。
API 还定义了storage事件,该事件将在与发生存储更改的文档相同的所有文档的window对象上调度,但不包括发生更改的窗口文档。对于其他 DOM 事件,如果您加载了一个页面并且调度了一个事件,则该事件将在当前页面上被调度。storage事件不会在当前页面调度。如果在选项卡中打开了同一页面的多个版本,则该事件将在除当前活动窗口对象之外的每个窗口对象上调度。
注意目前,Internet Explorer 会调度所有文档中的存储事件,而不仅仅是非活动文档。有一个针对当前被推迟的
https://connect.microsoft.com/IE/feedback/details/774798/localstorage-event-fired-in-source-window行为的 bug。
API 定义是:
interface Storage {
readonly unsigned long length;
DOMString? key(unsigned long index);
getter DOMString? getItem(DOMString key);
setter creator void setItem(DOMString key, DOMString value);
deleter void removeItem(DOMString key);
void clear();
};
interface WindowSessionStorage {
readonly attribute Storage sessionStorage;
};
interface WindowLocalStorage {
readonly attribute Storage localStorage;
};
localStorage和sessionStorage都实现了Storage接口,因此具有相同的方法:
getItem(key):返回与指定键相关的数据。removeItem(key):删除与指定键相关的数据。setItem(key, data):用指定的键将数据存储在存储器中。clear():清除所有内容的存储。
每当使用这些方法中的任何一种更改了localStorage时,就会在与当前文档相同的任何文档的window对象上调度一个storage事件。关联的event对象是一个StorageEvent对象,它具有以下属性:
target:target属性是对在其上调度事件的 DOM 元素的引用。在这种情况下,那就是window的对象。type:type属性设置为storage。key:key属性包含其相关数据已经改变的键。oldValue:oldValue属性包含数据的前一个值。newValue:newValue属性包含数据的新值。url:url属性包含托管文档的 URL。storageArea:storageArea属性将是对实际的localStorage对象的引用。
清单 8-5 演示了网络存储的使用。
清单 8-5 。使用 Web 存储
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
</head>
<body>
<h1>Web Storage Example</h1>
<script>
/**
* Handles a storage event.
* @param {StorageEvent} event The storage event object.
*/
function handleStorageEvent(event) {
var alertMsg = 'Storage event!\n';
alertMsg += 'key: ' + event.key + '\n';
alertMsg += 'oldValue: ' + event.oldValue + '\n';
alertMsg += 'newValue: ' + event.newValue + '\n';
alert(alertMsg);
}
// Register the event handler on the window object.
window.addEventListener('storage', handleStorageEvent, false);
// Check to see if we've visited this page before.
var myValue = localStorage.getItem('myKey');
if (myValue == null) {
alert('This is the first time you loaded this page! Now reload this page.');
localStorage.setItem('myKey', 'true');
} else {
alert('You have loaded this page before!');
localStorage.removeItem('myKey');
}
</script>
</body>
</html>
当你第一次加载这个例子时,它会告诉你这是你第一次加载这个页面。当您重新加载时,它会检测存储的信息,然后删除它,从而重置测试。如果在两个选项卡中打开示例,您将看到由非活动选项卡上调度的存储事件产生的警报。
表 8-4。网络存储标准
|
规格
|
状态
|
统一资源定位器
|
| --- | --- | --- |
| 万维网路联盟(World Wide Web Consortiumˌ简称 W3C) | 候选人推荐 | www.w3.org/TR/webstorage/ |
| WHATWG | 生活标准 | www.whatwg.org/specs/web-apps/current-work/multipage/webstorage.html |
拖放
新的 HTML5 拖放规范提供了一个本地 API 来处理浏览器中的拖放交互。API 是事件驱动的,使用它包括以下步骤:
- 将一个或多个对象声明为
draggable,并附加所需的事件处理程序。 - 将
drop事件处理程序附加到目标元素。 - 当用户拖动项目并将它们放到目标上时,会调度各种事件。
指定可拖动的元素:draggable属性
draggable属性是 DOM 元素的一个新属性,它指示元素作为拖动目标的可用性。该属性可以设置为三个值:
true:表示元素是可拖动的。false:表示元素不可拖动。auto:应用浏览器的默认规则。对于大多数元素,默认规则是false。(例外是选定的文本,它总是可以启动拖动交互。)
处理交互:拖放事件
API 指定了几个新事件,这些事件发生在拖动元素或它被拖动到的元素上:
dragstart:从被拖动的元素调度。dragenter:当一个可拖动的项目被拖动到任何元素中时,从该元素调度。dragover:从任何一个元素连续调度,只要一个可拖动的项目在它上面。请注意,无论可拖动项是否在移动,此事件都会连续触发。dragleave:当一个可拖动的项目离开它的边界时,从一个元素调度。drag:从整个拖动序列中被拖动的元素调度。像dragover一样,不管指针是否移动,这个事件都会被连续触发。dragend:从鼠标释放时被拖动的元素调度。drop:当用户通过释放鼠标按钮将可拖动的项目放到元素上时,从元素调度。
指定投放目标
API 指定了一个dropzone属性,该属性应该指示元素可以是放置目标。然而,dropzone属性没有得到广泛的支持,所以指定给定元素是有效目标的唯一方法是通过事件处理程序。
一般来说,DOM 中的大多数元素不应该是有效的放置目标,所以dragover事件的默认动作是取消放置。因此,为了指示一个有效的拖放目标,您必须通过调用事件处理程序中的event对象上的preventDefault()方法来取消dragover事件的默认动作。
dataTransfer物体
所有的拖放事件都可以用标准的事件处理程序来处理,这些事件处理程序将接收一个event对象作为参数。拖放的event对象的属性之一是dataTransfer对象。该对象用于控制拖放助手的外观(在拖放操作中跟随光标的幻影可视元素),指示拖放过程正在做什么,并轻松地将数据从dragstart事件传输到drop事件。
dataTransfer对象有以下方法:
Event.dataTransfer.addElement(HtmlElement):指定拖动序列的源元素。这会影响到drag和dragend事件的触发位置。这是在拖动交互开始时自动设置的,所以您可能不需要更改它。Event.dataTransfer.clearData(opt_DataType):清除与特定DataType相关的数据(见该列表中的setData)。如果未指定DataType,所有数据将被清除。Event.dataTransfer.getData(DataType):获取与特定DataType相关的数据(见setData,下一步)。Event.dataTransfer.setData(DataType, data):将指定的data与DataType关联。有效的DataTypes取决于浏览器。Internet Explorer 只支持text和url的DataTypes。其他浏览器支持标准 MIME 类型,甚至任意类型。data必须是一个简单的字符串,但也可以是 JSON 格式的序列化对象。请注意,Firefox 要求在dragstart事件期间用数据初始化dataTransfer对象,以便正确触发拖放事件。Event.dataTransfer.setDragImage(HtmlElement, opt_offsetX, opt_offsetY):将拖动辅助图像设置为指定的 HTML 元素。默认情况下,辅助图像的左上角位于鼠标指针的下方,但是可以通过指定可选参数opt_offsetX和opt_offsetY进行偏移,以像素为单位。此方法在 Internet Explorer 中不可用,而且显然永远不会可用;参见http://connect.microsoft.com/IE/feedback/details/804304/implement-datatransfer-prototype-setdragimage-method。
dataTransfer对象还具有以下属性:
Event.dataTransfer.dropEffect:拖放序列正在执行的拖放效果。有效值为copy、move、link和none。该值在dragenter和dragover事件中根据用户通过鼠标动作和修饰键的组合(例如,Ctrl-拖动、Shift-拖动、Option-拖动等)所请求的交互来自动初始化。).这些依赖于平台。只有由effectAllowed(见下一页)指定的值才会真正启动拖放序列。Event.dataTransfer.effectAllowed:指定该拖放序列允许哪些dropEffects。有效值及其允许的效果如下:copy:允许复制dropEffect。move:允许移动dropEffect。link:允许链接dropEffect。copyLink:允许复制和链接dropEffect。copyMove:允许复制和移动dropEffect。linkMove:允许链接和移动dropEffect。all:所有dropEffects都是允许的。这是默认值。none:不允许dropEffects(该物品不能被丢弃)。
Event.dataTransfer.files:包含数据传输中所有可用文件的列表。只有将文件从桌面拖到浏览器时,才会有值。Event.dataTransfer.types:包含所有已经添加到dataTransfer对象中的DataTypes的列表,按照添加的顺序排列。
清单 8-6 展示了拖放 API。
清单 8-6 。拖放 API 在工作
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style type="text/css">
#drag-target,
#drop-target {
float: left;
padding: 10px;
margin: 10px;
box-sizing: border-box;
}
#drag-target {
background-color: #008000;
width:75px;
height:75px;
}
#drop-target {
background-color: #0000FF;
width:150px;
height:150px;
}
.drag-over {
border: 5px solid #FF0000;
}
</style>
</head>
<body>
<h1>Drag and Drop Example</h1>
<div id="drop-target">Target</div>
<div id="drag-target" draggable="true">Drag me!</div>
<script>
/**
* Handles a dragStart event.
* @param {DragEvent} event The event object.
*/
function handleDragStart(event) {
// Set the data in the dataTransfer object to the id of the element being
// dragged.
event.dataTransfer.setData("Text", event.target.getAttribute('id'));
}
/**
* Handles a dragenter event.
* @param {DragEvent} event The event object.
*/
function handleDragEnter(event) {
// Apply a class to the element.
event.target.classList.add('drag-over');
}
/**
* Handles a dragleave event.
* @param {DragEvent} event The event object.
*/
function handleDragLeave(event) {
// Remove the class from the element.
event.target.classList.remove('drag-over');
}
/**
* Handles a dragover event.
* @param {DragEvent} event The event object.
*/
function handleDragOver(event) {
// Indicates this element is a valid drop target.
event.preventDefault();
}
/**
* Handles a drop event.
* @param {DragEvent} event The event object.
*/
function handleDrop(event) {
// Get a reference to the dragging element and append it to the drop target.
var src = event.dataTransfer.getData("Text");
event.target.appendChild(document.getElementById(src));
event.preventDefault();
}
// Register event handlers.
var dragTarget = document.getElementById('drag-target');
dragTarget.addEventListener('dragstart', handleDragStart);
var dropTarget = document.getElementById('drop-target');
dropTarget.addEventListener('dragenter', handleDragEnter);
dropTarget.addEventListener('dragleave', handleDragLeave);
dropTarget.addEventListener('dragover', handleDragOver);
dropTarget.addEventListener('drop', handleDrop);
</script>
</body>
</html>
当您运行这个示例时,您将能够拖动拖动目标(标记为“拖动我!”)放入拖放目标(标记为“目标”)。它在dragstart事件期间将dataTransfer对象中的数据设置为拖动目标的 ID,然后在drop事件期间检索它,并使用它来获取对元素的引用,并将它移动到 DOM 中。这是拖放 API 的一个非常常见的用例。
表 8-5。拖放的标准
|
规格
|
状态
|
统一资源定位器
|
| --- | --- | --- |
| 万维网路联盟(World Wide Web Consortiumˌ简称 W3C) | 建议 | www.w3.org/TR/html5/editing.html#dnd |
| WHATWG | 生活标准 | www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html |
网络工作者
Web Workers API 使您能够通过创建(或“生成”)子进程来处理某些任务,从而创建线程化的 JavaScript 应用。每个工作器都运行自己的 JavaScript 上下文,并执行您为其设置的任何任务。Web worker 也可以产生其他 Web worker。
Web Worker 上下文和主 JavaScript 线程之间的通信是通过一个类似于 Web 消息传递所使用的postMessage接口来完成的。这使您能够将数据传入和传出 Web Worker 上下文,但是因为所有上下文都是独立的,所以在上下文之间传递的任何数据都会被复制,除非您专门传输它。(有关使用postMessage发送和传输数据的更多详细信息,请参见前面的“跨文档消息传递/Web 消息传递”部分)。
当您创建一个新的 Web Worker 时,您为它指定一个 JavaScript 文件来加载和运行。要启动它,向它发送一条消息(任何消息都可以)。工作线程可以将消息发送回父上下文或它可以访问的任何其他 Web 工作线程。
Web 工作者有一些重要的限制,旨在帮助避免编写多线程应用时固有的常见缺陷:
- Web Worker 运行在自己独立的 JavaScript 上下文中。它不能直接访问任何其他执行上下文中的任何内容,比如其他 Web Workers 或主 JavaScript 线程。
- Web Worker 上下文和主 JavaScript 线程之间的通信是通过一个类似于 Web 消息传递所使用的
postMessage接口来完成的。这使您能够将数据传入和传出 Web Worker 上下文,但是因为所有上下文都是独立的,所以在上下文之间传递的任何数据都是复制的,而不是共享的。 - Web Worker 无法访问 DOM。Web 工作者可以使用的 DOM 方法只有
atob、btoa、clearInterval、clearTimeout、dump、setInterval和setTimeout。 - Web Workers 受相同来源策略的约束,因此您不能从不同于原始脚本的来源加载 worker 脚本。
Web Workers API 在全局 JavaScript 作用域中采用了新的WebWorker构造函数的形式:
constructor WebWorker(DOMstring url)
interface WebWorker implements EventTarget {
readonly WorkerLocation location;
void terminate();
OnErrorEventHandler onerror;
EventHandler onlanguagechange;
EventHandler onoffline;
EventHandler ononline;
EventHandler onmessage;
};
语法
var myWorker = new WebWorker('worker-script.js');
构造函数返回一个WebWorker对象,它实现了EventTarget接口。这些属性是:
location:location属性类似于document.location对象,但是包含特定于 Web Worker 的信息(详见下文)。terminate():terminate方法将为工作线程结束线程。一旦工人被解雇,就不可能重新开始。onerror:当一个error事件在 worker 上调度时,调用onerror事件处理程序。onlanguagechange:当用户在浏览器中更改他们的首选语言时,在 worker 上调度onlanguagechange处理程序。onoffline:当一个offline事件在 worker 上调度时,调用onoffline事件处理程序。当浏览器失去网络连接并且navigator.onLine的值更改为false时,就会出现这种情况。ononline:当一个online事件在 worker 上调度时,调用ononline事件处理程序。当浏览器恢复网络连接时,会出现这种情况。onmessage:当一个message事件在 worker 上调度时,调用onmessage事件处理程序。
Web Worker 内部的执行上下文与全局执行上下文明显不同。Web 工作人员无权访问 DOM,但他们可以访问以下属性和方法:
-
DOM 方法
atob、btoa、clearInterval、clearTimeout、dump、setInterval和setTimeout。 -
XMLHttpRequest构造函数,因此 Web 工作者可以执行异步网络任务。 -
WebSocket构造函数,因此 Web 工作者可以创建和管理 Web 套接字(在撰写本文时,Firefox 没有为 Web 工作者启用WebSocket;不过,这个功能正在实现中,你可以在https://bugzilla.mozilla.org/show_bug.cgi?id=504553跟踪它的状态 -
Worker构造函数,因此 Web workers 可以产生自己的 Workers(称为“子 Workers”)。截至本文撰写之时,Chrome 和 Safari 还没有为 Web Workers 实现Worker构造函数。在https://code.google.com/p/chromium/issues/detail?id=31666的 Chrome 和https://bugs.webkit.org/show_bug.cgi?id=22723的 Safari 的 WebKit 都有一个 bug。从版本 10 开始,Internet Explorer 支持子工作器。 -
EventSource构造函数,因此 Web 工作者可以订阅服务器发送的事件流。这似乎是一个非标准特性,但是在撰写本文时,似乎在所有主流浏览器中都可以使用。 -
Navigator属性的特殊子集,可通过navigator对象获得:-
navigator.language:返回浏览器当前使用的语言。 -
navigator.onLine:返回一个布尔值,表示浏览器是否在线。 -
navigator.platform:返回表示主机系统平台的字符串。 -
navigator.product:返回当前浏览器名称的字符串。 -
navigator.userAgent: Returns the user agent string for the browser.这些属性的实现因浏览器而异,因此最好将所需的
Navigator信息从主线程传递给 Web Worker。
-
-
在
location对象上可用的Location属性的特殊子集:location.href:Web Worker 正在执行的脚本的完整 URL。location.protocol:Web Worker 正在执行的脚本的 URL 的协议方案,包括最后的“:”。location.host:Web Worker 正在执行的脚本的 URL 的主机部分(主机名和端口)。location.hostname:Web Worker 正在执行的脚本的 URL 的主机名部分。location.port:Web Worker 正在执行的脚本的 URL 的端口部分。location.pathname:首字母“/”,后跟 Web Worker 正在执行的脚本的路径。location.search:初始'?'后跟 Web Worker 正在执行的脚本的 URL 的参数(如果有的话)。location.hash:Web Worker 正在执行的脚本的 URL 的片段标识符(如果有的话)后面的首字母' # '。
除此之外,Web 工作者还有一个特殊的方法只有他们可以使用:importScripts。该方法接受 JavaScript 文件的单个 URL 或以逗号分隔的 URL 列表,并按顺序加载和执行。importScripts方法是一个阻塞方法,并且受同源策略的约束。
语法
importScripts('test.js');
importScripts('polymer.js', 'custom-element.js', 'jquery.js');
当 Web Worker 启动时,它遵循以下步骤:
- 它从头到尾执行脚本,包括任何异步任务(比如
XMLHttpRequest调用)。 - 如果其执行的一部分是注册一个
message事件处理程序,那么它将进入一个wait循环来接收消息。它收到的第一条消息将是发布来启动工作进程的消息。工作线程将保持等待模式,直到您手动终止它,或者它自己终止。 - 如果没有注册
message事件处理程序,工作线程将自动终止。
为了演示一个 Web worker,您需要两个文件:一个创建和运行 Worker 的宿主页面,以及一个供 Worker 执行的独立 JavaScript 脚本。清单 8-7 显示了一个基本的主机页面。
清单 8-7 。创建并使用 Web Worker
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
</head>
<body>
<h1>Web Workers</h1>
<div id="message-box"></div>
<script>
/**
* Handles an error event from web worker.
* @param {WorkerErrorEvent} event The error event object.
*/
function handleWorkerError(event) {
console.warn('Error in web worker: ', event.message);
}
/**
* Handles a message event from a web worker.
* @param {WorkerMessageEvent} event The message event object.
*/
function handleWorkerMessage(event) {
displayMessage('Message received from worker: ' + event.data);
}
/**
* Displays a message in the message box.
* @param {string} message The message to display.
*/
function displayMessage(message) {
// Get a reference to the target element.
var messageBox = document.getElementById('message-box');
// Create a new paragraph and set its content to the message.
var newParagraph = document.createElement('p');
newParagraph.innerHTML = message;
// Append the new paragraph to the target element.
messageBox.appendChild(newParagraph);
}
// Create a new worker.
var myNewWorker = new Worker('example8-8.js');
// Register error and message event handlers on the worker.
myNewWorker.addEventListener('error', handleWorkerError);
myNewWorker.addEventListener('message', handleWorkerMessage);
// Start the worker.
myNewWorker.postMessage('begin');
</script>
</body>
</html>
对于网络工作者来说,清单 8-8 是一个非常基本的独立脚本。
清单 8-8 。一个简单的 Web Worker 脚本
/**
* Handles a message event from the main context.
* @param {WorkerMessageEvent} event The message event.
*/
function handleMessageEvent(event) {
// Do something with the message.
console.log('Worker received message:', event.data);
// Send the message back to the main context.
self.postMessage('Your message was received.');
}
// Register the message event handler.
self.addEventListener('message', handleMessageEvent);
// Dispatch 10 events to the host document.
var counter = 0;
var timer = setInterval(function() {
counter++;
self.postMessage('Message #' + counter);
if (counter == 10) {
// Stop the timer.
clearInterval(timer);
// Throw an error.
throw new Error();
}
}, 1000);
注意本例中的文件需要在常规服务器上提供,代码才能运行。如果您只是简单地从文件系统加载主机文件到浏览器中,浏览器将抛出一个跨原点冲突错误。
表 8-6。网络工作者的标准
|
规格
|
状态
|
统一资源定位器
|
| --- | --- | --- |
| 万维网路联盟(World Wide Web Consortiumˌ简称 W3C) | 建议 | http://dev.w3.org/html5/workers/ |
| WHATWG | 生活标准 | www.whatwg.org/specs/web-apps/current-work/multipage/workers.html |
九、画布参考
本章将为canvas元素和 2D 绘图上下文 API 提供详细参考。有关这些功能的详细讨论和更多示例,请参见第四章。
canvas元素
HTML5 canvas元素通过提供一个空白的“画布”让你在网页上绘制位图。canvas元素本身是一个块级 DOM 元素。要使用canvas元素进行绘图,您必须从元素中获取一个绘图上下文引用。该上下文公开了一个用于绘图的扩展 API,您可以在脚本中使用它。
canvas元素本身的 API 定义是:
Interface HTMLCanvasElement implements HTMLElement {
unsigned long width;
unsigned long height;
renderingContext? getContext(DOMString contextId);
DOMString toDataURL(optional DOMString type);
}
语法
<canvas id="myCanvas" width="100" height="100"></canvas>
<script>
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
</script>
属性是
width:元素的布局宽度。height:元素的布局高度。getContext():返回请求的渲染上下文。所有的浏览器都支持'2D'上下文,并且许多支持'webgl'(在旧的浏览器中,'experimental-webgl')上下文。toDataURL():返回画布位图的数据 URI 表示。可选的 type 参数用于指定编码数据的格式。有效选项为"image/jpeg"、"image/gif"或"image/png"。如果没有指定类型参数,默认为"image/png"。编码图像的分辨率为 96dpi。
提示数据 URI 方案是一种将数据直接编码成文档的方式。您可以在数据 URI 中编码任何内容,但它最常用于编码图像。当图像被编码为数据 URI 时,您就可以在使用常规 URL 的地方使用该数据 URI(例如,在图像标签的
src属性中)。数据 URIs 在 RFC 2397 中的tools.ietf.org/html/rfc2397 处定义。
您需要使用标签本身的width和height`属性来指定画布元素的宽度和高度,而不是使用 CSS。如果使用 CSS,绘图上下文的纵横比将会不正确(除非您指定 canvas 元素的默认大小,即 200 像素高,400 像素宽)。
清单 9-1 展示了一个canvas元素的基本实现。
清单 9-1 。一个canvas元素
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200"></canvas>
<script>
// Get a DOM reference to the canvas element.
var myCanvas = document.getElementById('myCanvas');
// Get a reference to the 2d drawing context from the canvas element.
var myContext = myCanvas.getContext('2d');
</script>
</body>
</html>
表 9-1。canvas元素的标准
|
规格
|
状态
|
统一资源定位器
|
| --- | --- | --- |
| 万维网路联盟(World Wide Web Consortiumˌ简称 W3C) | 候选人推荐 | www.w3.org/TR/2dcontext/ |
| WHATWG | 生活标准 | www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html |
绘图环境
一旦创建了一个canvas元素并从中检索到绘图上下文,就可以使用绘图上下文上的 API 开始绘图。2d 绘图上下文是最常用的绘图上下文,其 API 将在本章中介绍。API 提供的命令很简单,但提供了创建复杂图形所需的所有工具。
2d 绘图上下文使用笔的隐喻来进行绘图,这意味着大多数绘制某物的命令采取“从笔的当前位置,绘制该项”或“从笔的当前位置绘制该项”的形式 2d 环境也采用了路径的概念。一个路径是你刚刚绘制的项目的一个不可见的表示,无论它是一条线,一个圆,还是由多个项目组成的复杂的绘图。路径可以是描边的(表示绘制路径时就像用钢笔描边一样)或填充的(表示路径包含的所有区域都被填充)。可以用纯色、渐变或从图像生成的图案来描边和填充路径。路径可以是开放的(起点和终点不同)或封闭的(起点和终点相同)。它们不必是连续的;您可以拥有一条包含几个不相连的“片段”的路径。2d 绘图上下文一次仅支持一个活动路径。
定义路径
2d 绘图上下文提供了一些用于定义路径的简单命令。
beginPath法
此命令指定您正在定义一个新路径。先前的路径将从绘图上下文中清除。
语法
Context.beginPath();
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.beginPath();
closePath法
该命令关闭当前路径。如果当前路径的起点和终点不相同(换句话说,如果当前路径还没有闭合),该命令将通过沿两点之间的直线延伸来闭合路径。
语法
Context.closePath();
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.closePath();
moveTo法
此命令将笔移动到指定的坐标。这提供了一种创建不连续路径的方法。
语法
Context.moveTo(x, y);
表 9-2。moveTo方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | x | 数字 | 新位置的 x 坐标。 | | y | 数字 | 新位置的 y 坐标。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.moveTo(10, 10);
清单 9-2 展示了在绘图环境中创建和管理路径。
清单 9-2 。管理路径
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Set the stroke style.
myContext.strokeStyle = '#000000';
myContext.lineWidth = 5;
// Create a closed path.
myContext.beginPath();
// Start the path at (30, 10).
myContext.moveTo(30, 10);
// Draw a line from the current pen location at (30, 10) to (50, 50).
myContext.lineTo(50, 50);
// Draw a line from current pen location at (50, 50) to (10, 50);
myContext.lineTo(10, 50);
// The pen is now currently at (10, 50). Closing the path will draw a straight
// line from (10, 50) back to the beginning point of the path at (30, 10).
myContext.closePath();
// We can't see the path without stroking it.
myContext.stroke();
// Create a new path.
myContext.beginPath();
// Start the path at (60, 10).
myContext.moveTo(60, 10);
// Draw a line from the current pen location at (60, 10) to (100, 10).
myContext.lineTo(100, 10);
// Move the pen from its current location at (100, 10) to (100, 50).
myContext.moveTo(100, 50);
// Draw a line from the current pen location at (100, 50) to (60, 50).
myContext.lineTo(60, 50);
// Give the new shape a different color.
myContext.strokeStyle = '#ff0000';
myContext.stroke();
// Creating a new path will clear the current path from memory without closing
// the previous one. We can demonstrate this by changing the stroke style and
// calling stroke again. The previous shape should remain red.
myContext.beginPath();
myContext.strokeStyle = '#00ff00';
myContext.stroke();
</script>
</body>
</html>
基本绘图命令
2d 绘图上下文提供了一组绘制曲线的方法:直线、圆弧等。
lineTo法
此命令绘制从当前笔位置到指定坐标的路径。
语法
Context.lineTo(x, y);
表 9-3。lineTo方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | x | 数字 | 所需端点的 x 坐标。 | | y | 数字 | 所需端点的 y 坐标。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.lineTo(10, 10);
arc法
沿着以坐标(x, y)为圆心,半径radius的圆,从startAngle到endAngle画一个圆弧。
语法
Context.arc(x, y, radius, startAngle, endAngle, opt_isAnticlockwise);
表 9-4。arc方法的参数
|
参数
|
类型
|
说明
|
| --- | --- | --- |
| x | 数字 | 所需中心的 x 坐标。 |
| y | 数字 | 所需中心的 y 坐标。 |
| 半径 | 数字 | 弧的半径,以像素为单位。 |
| 半径 | 数字 | 以弧度表示的起始角度。 |
| 结束角度 | 数字 | 以弧度表示的结束角度。 |
| opt _ isatical lock wise-选项 isanticlockwise | 布尔代数学体系的 | 如果true,圆弧将逆时针画出。可选;如果未提供,默认为false。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Draw an arc starting from 0 to 3 radians.
myContext.arc(50, 50, 10, 0, 3);
quadraticCurveTo法
该命令绘制一条二次曲线,从当前笔位置开始,到坐标(x, y)结束,控制点在(cp1x, cp1y)。
语法
Context.quadraticCurveTo(cplx, cply, x, y);
表 9-5。quadraticCurveTo方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | cplex(葡语共同体) | 数字 | 控制点的 x 坐标。 | | cply | 数字 | 控制点的 y 坐标。 | | x | 数字 | 曲线终点的 x 坐标。 | | y | 数字 | 曲线终点的 y 坐标。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.quadraticCurveTo(50, 50, 10, 10);
bezierCurveTo法
绘制一条贝塞尔曲线,从当前笔位置开始,到坐标(x, y)结束,控制点 1 由(cp1x, cp1y)指定,控制点 2 由(cp2x, cp2y)指定。
语法
Context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
表 9-6。bezierCurveTo方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 缔约方会议第一届会议 | 数字 | 控制点 1 的 x 坐标。 | | cp 1 和 | 数字 | 控制点 1 的 y 坐标。 | | cp2x(缔约方会议第二届会议) | 数字 | 控制点 2 的 x 坐标。 | | cp 2 和 | 数字 | 控制点 2 的 y 坐标。 | | x | 数字 | 终点的 x 坐标。 | | y | 数字 | 终点的 y 坐标。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.bezierCurveTo(50, 50, 10, 10);
rect法
该命令从坐标(x, y)开始绘制一个矩形,指定了width和height。
语法
Context.rect(x, y, width, height);
表 9-7。rect方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | x | 数字 | 左上角的 x 坐标。 | | y | 数字 | 左上角的 y 坐标。 | | 宽度 | 数字 | 矩形的宽度,以像素为单位。 | | 高度 | 数字 | 矩形的高度,以像素为单位。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.rect(50, 50, 10, 10);
描边和填充路径
如前所述,基本的绘图命令在画布上创建不可见的路径。要使路径可见,必须使用描边或填充命令。2d 绘图上下文还提供了一组用于定义笔画和填充样式的属性。
strokeStyle属性
该属性指定了在对stroke方法的后续调用中应该应用的样式。该属性可以接受任何有效的 CSS 颜色字符串(例如,'red'、'#ff0000'、'rgb(255, 0, 0)'等)。),一个Gradient对象,或者一个Pattern对象。(参见下文,了解如何定义Gradient和Pattern对象。)
语法
Context.strokeStyle = StrokeStyleValue;
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.strokeStyle = '#FF0000';
stroke法
此命令用当前设置的描边样式描边当前路径。
语法
Context.stroke();
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.strokeStyle = '#FF0000';
myContext.strokePath();
fillStyle属性
该属性指定了在对fill方法的后续调用中应该应用的样式。该属性可以接受任何有效的 CSS 颜色字符串(例如,'red'、'#ff0000'、'rgb(255, 0, 0)'等)。),一个Gradient对象,或者一个Pattern对象。(参见下文,了解如何定义Gradient和Pattern对象。)
语法
Context.fillStyle = FillStyleValue;
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.fillStyle = '#FF0000';
fill法
该命令用当前设置的填充样式填充当前路径。
语法
Context.fill();
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.fillStyle = '#FF0000';
myContext.fillPath();
lineWidth属性
此属性以应用于路径的描边为单位定义粗细。如果没有设置,该属性默认为 1。
语法
Context.lineWidth = Number;
表 9-8。lineCap属性的值
|
价值
|
说明
| | --- | --- | | 屁股 | 线端被切成方形,并精确地终止于指定的端点。这是默认值。 | | 圆形物 | 线条端点是圆形的,并稍微超出指定的端点。 | | 平方 | 通过在线条末端添加一个宽度等于线条宽度、高度为线条宽度一半的方框,线条末端被方形化。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.lineWidth = 2;
lineCap属性
此属性定义如何封闭线条。有效值为'butt'、'round'或'square'。
语法
Context.lineCap = LineCapValue;
表 9-9。lineJoin属性的值
|
价值
|
说明
| | --- | --- | | 斜角规 | 接缝是斜的。 | | 斜接 | 接缝是斜接的。 | | 圆形物 | 关节是圆形的。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.lineCap = 'round';
lineJoin属性
此属性定义连接线如何连接在一起。有效值为'bevel'、'miter'或'round'。
语法
Context.lineJoin = LineCapValue;
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.lineJoin = 'round';
清单 9-3 提供了一个使用基本绘图命令和填充和描边命令来创建函数的例子,这些函数可以很容易地画出圆。
清单 9-3 。圆圈耶
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
/**
* Draws a circle of the specified dimensions at the target coordinates and
* fills it with the current fill style.
* @param {number} x The x coordinate of the center of the circle.
* @param {number} y The y coordinate of the center of the circle.
* @param {number} radius The radius of the circle.
*/
function fillCircle(x, y, radius) {
myContext.beginPath();
myContext.arc(x, y, radius, 0, 6.3);
myContext.fill();
myContext.closePath();
}
/**
* Draws a circle of the specified dimensions at the target coordinates and
* strokes it with the current stroke style.
* @param {number} x The x coordinate of the center of the circle.
* @param {number} y The y coordinate of the center of the circle.
* @param {number} radius The radius of the circle.
*/
function strokeCircle(x, y, radius) {
myContext.beginPath();
myContext.arc(x, y, radius, 0, 6.3);
myContext.stroke();
myContext.closePath();
}
// Set a fill style and draw a filled circle.
myContext.fillStyle = 'rgb(0, 0, 0)';
fillCircle(65, 65, 50);
// Set a stroke style and draw a stroked circle.
myContext.strokeStyle = 'rgb(0, 0, 0)';
myContext.lineWidth = 2;
strokeCircle(135, 135, 50);
</script>
</body>
</html>
绘制矩形
除了基本路径之外,2d 绘图上下文还有一些用于绘制简单矩形的功能。您可以用基本的路径命令来绘制这些,但是这些方便的方法使它更容易。
fillRect法
该命令在指定坐标处绘制一个具有指定宽度和高度的矩形,并用当前填充样式填充。
语法
Context. fillRect(x, y, width, height);
表 9-10。fillRect方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | x | 数字 | 左上角的 x 坐标。 | | y | 数字 | 左上角的 y 坐标。 | | 宽度 | 数字 | 矩形的宽度,以像素为单位。 | | 高度 | 数字 | 矩形的高度,以像素为单位。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.fillStyle = '#000000';
myContext.fillRect(50, 50, 10, 10);
strokeRect法
此命令在指定的坐标处绘制一个矩形,该矩形具有指定的宽度和高度,并使用当前的描边样式描边。
语法
Context. strokeRect(x, y, width, height);
表 9-11。strokeRect方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | x | 数字 | 左上角的 x 坐标。 | | y | 数字 | 左上角的 y 坐标。 | | 宽度 | 数字 | 矩形的宽度,以像素为单位。 | | 高度 | 数字 | 矩形的高度,以像素为单位。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.strokeStyle = '#000000';
myContext.strokeRect(50, 50, 10, 10);
clearRect法
该命令清除任何其他图形的指定矩形区域。
语法
Context. clearRect(x, y, width, height);
表 9-12。clearRect方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | x | 数字 | 左上角的 x 坐标。 | | y | 数字 | 左上角的 y 坐标。 | | 宽度 | 数字 | 矩形的宽度,以像素为单位。 | | 高度 | 数字 | 矩形的高度,以像素为单位。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.clearRect(50, 50, 10, 10);
清单 9-4 演示了矩形的绘制。
清单 9-4 。随机矩形
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Create a loop that will draw a random rectangle on the canvas.
var cycles = 10,
i = 0;
for (i = 0; i < cycles; i++) {
var randX = getRandomIntegerBetween(0, 150);
var randY = getRandomIntegerBetween(0, 150);
var randWidth = getRandomIntegerBetween(10, 100);
var randHeight = getRandomIntegerBetween(10, 100);
myContext.beginPath();
myContext.strokeRect(randX, randY, randWidth, randHeight);
randStroke();
myContext.closePath();
}
/**
* Returns a random integer between the specified minimum and maximum values.
* @param {number} min The lower boundary for the random number.
* @param {number} max The upper boundary for the random number.
* @return {number}
*/
function getRandomIntegerBetween(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
/**
* Returns a random color formatted as an rgb string.
* @return {string}
*/
function getRandRGB() {
var randRed = getRandomIntegerBetween(0, 255);
var randGreen = getRandomIntegerBetween(0, 255);
var randBlue = getRandomIntegerBetween(0, 255);
return 'rgb(' + randRed + ', ' + randGreen + ', ' + randBlue + ')';
}
/**
* Performs a randomized stroke on the current path.
*/
function randStroke() {
myContext.lineWidth = getRandomIntegerBetween(1, 10);
myContext.strokeStyle = getRandRGB();
myContext.stroke();
}
</script>
</body>
</html>
渐变和图案
Canvas has great support for gradients and patterns. Both patterns and gradients are represented by objects returned from construction functions. These objects can then be used as the values for fill or stroke styles.
createLinearGradient法
该方法创建一个从坐标(startX, startY)开始到坐标(endX, endY)结束的线性渐变。返回一个可用作描边或填充样式的Gradient对象。
语法
Context.createLinearGradient(startX, startY, endX, endY);
表 9-13。createLinearGradient方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 启动 X | 数字 | 渐变起点的 x 坐标。 | | 起始 Y | 数字 | 渐变起点的 y 坐标。 | | endX(结束 x) | 数字 | 渐变终点的 x 坐标。 | | 周国贤 | 数字 | 渐变终点的 y 坐标。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
var myGradient = myContext.createLinearGradient(50, 50, 10, 10);
createRadialGradient法
该方法创建一个由两个圆组成的径向渐变,第一个以(x, y)为中心,半径为r,另一个以(x1, y1)为中心,半径为r1。返回一个可用作描边或填充样式的Gradient对象。
语法
Context.createRadialGradient(x, y, r, x1, y1, r1);
表 9-14。createRadialGradient方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | x | 数字 | 第一个圆的圆心的 x 坐标。 | | y | 数字 | 第一个圆的圆心的 y 坐标。 | | r | 数字 | 第一个圆的半径。 | | x1 | 数字 | 第二个圆的圆心的 x 坐标。 | | y1 | 数字 | 第二个圆的圆心的 y 坐标。 | | r1 | 数字 | 第二个圆的半径。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
var myGradient = myContext.createRadialGradient(50, 50, 50, 50, 50, 100);
addColorStop法
该命令为Gradient添加一个色标。position 参数必须介于 0 和 1 之间,并定义色标渐变内的相对位置。颜色可以是任何有效的 CSS 颜色值。您可以为特定的Gradient添加任意数量的色标。
语法
Gradient.addColorStop(position, color);
表 9-15。lineTo方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 位置 | 数字 | 色标的位置。 | | 颜色 | CssColorValue | 色标的颜色。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
var myGradient = myContext.createRadialGradient(50, 50, 50, 50, 50, 100);
myGradient.addColorStop(0, '#FF0000');
myGradient.addColorStop(1, '#000000');
createPattern法
该命令创建一个可用作填充或描边样式的Pattern对象。Image参数必须是任何有效的Image(详见下一节“图像”)。repeat参数指定图案图像如何重复,必须是'repeat'、'repeat-x'、'repeat-y'或'no-repeat'之一。
语法
Gradient.createPattern(position, color);
表 9-16。createPattern方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 图像 | 图像 | 用于创建图案的图像。 | | 重复 | 线 | 如何重复图像来创建图案。 |
表 9-17。重复参数的有效值
|
价值
|
说明
| | --- | --- | | 重复 | 水平和垂直平铺图像。 | | 重复-x | 仅水平重复图像。 | | 重复-y | 仅垂直重复图像。 | | 不重复 | 完全不要重复图像。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
var myImage = document.getElementById('myImage');
var myPattern = myContext.createPattern(myImage, 'repeat');
清单 9-5 演示了使用径向渐变填充随机圆。
清单 9-5 。生成并使用径向渐变填充形状
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
/**
* Draws a circle of the specified dimensions at the target coordinates and
* fills it with the current fill style.
* @param {number} x The x coordinate of the center of the circle.
* @param {number} y The y coordinate of the center of the circle.
* @param {number} radius The radius of the circle.
*/
function fillCircle(x, y, radius) {
myContext.beginPath();
myContext.arc(x, y, radius, 0, 6.3);
myContext.fill();
myContext.closePath();
}
/**
* Returns a random integer between the specified minimum and maximum values.
* @param {number} min The lower boundary for the random number.
* @param {number} max The upper boundary for the random number.
* @return {number}
*/
function getRandomIntegerBetween(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
/**
* Returns a random color formatted as an rgb string.
* @return {string}
*/
function getRandRGB() {
var randRed = getRandomIntegerBetween(0, 255);
var randGreen = getRandomIntegerBetween(0, 255);
var randBlue = getRandomIntegerBetween(0, 255);
return 'rgb(' + randRed + ', ' + randGreen + ', ' + randBlue + ')';
}
// Create a loop that will draw a random circle on the canvas.
var cycles = 10,
i = 0;
for (i = 0; i < cycles; i++) {
// Get a random set of coordinates for the new circle.
var randX = getRandomIntegerBetween(50, 150);
var randY = getRandomIntegerBetween(50, 150);
// Get a random radius.
var randRadius = getRandomIntegerBetween(10, 50);
// Create a gradient object based on the coordinates we just generated.
var randGrad = myContext.createRadialGradient(randX, randY, 0, randX, randY,
randRadius);
// Create some random colors and add them as color stops to the gradient.
var randColor1 = getRandRGB();
var randColor2 = getRandRGB();
randGrad.addColorStop(0, randColor1);
randGrad.addColorStop(1, randColor2);
// Set the fill style and draw the circle.
myContext.fillStyle = randGrad;
fillCircle(randX, randY, randRadius);
}
</script>
</body>
</html>
形象
2d 绘图上下文还可以加载和操作图像。有效的图像源是一个img元素、video元素或另一个canvas元素。图像源不必作为 DOM 的一部分呈现,因此您可以根据需要动态创建标签和加载内容,而不必将它们附加到 DOM。一旦图像被加载到canvas中,您也可以使用绘图命令在其上绘图。
Canvas有一个绘制图像的方法drawImage,但是它可以接受许多不同的参数,因此具有多种功能。
画一幅图像
当您为 drawImage 提供一个图像源、一个 x 坐标和一个 y 坐标时,它将在坐标处绘制图像。
语法
Context.drawImage(image, x, y);
表 9-18。简单绘制图像时drawImage方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 图像 | CanvasImageSource | 有效的画布图像源。 | | x | 数字 | 图像的 x 坐标。 | | y | 数字 | 图像的 y 坐标。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
var myImage = document.getElementById('myImage');
myContext.drawImage(myImage, 10, 10);
缩放图像
当您给drawImage提供一个图像源、一个 x 坐标、一个 y 坐标、一个宽度和一个高度时,它将在这些坐标处绘制图像,并将图像缩放到指定的width和height。
语法
Context.drawImage(image, x, y, width, height);
表 9-19。缩放图像时drawImage方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 图像 | CanvasImageSource | 有效的画布图像源。 | | x | 数字 | 图像的 x 坐标。 | | y | 数字 | 图像的 y 坐标。 | | 宽度 | 数字 | 图像的所需宽度,以像素为单位。 | | 高度 | 数字 | 图像的所需高度,以像素为单位。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
var myImage = document.getElementById('myImage');
myContext.drawImage(myImage, 10, 10, 50, 50);
绘制图像的切片
您也可以选择图像上的特定区域(“切片”),并在画布上绘制该区域。
语法
Context.drawImage(image, sliceX, sliceY, sliceWidth, sliceHeight, x, y);
表 9-20。绘制图像切片时,drawImage方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 图像 | CanvasImageSource | 有效的画布图像源。 | | sliceX | 数字 | 切片左上角图像上的 x 坐标。 | | 微笑的 | 数字 | 切片左上角图像的 y 坐标。 | | 切片宽度 | 数字 | 所需的切片宽度,以像素为单位。 | | 切片高度 | 数字 | 切片的所需高度,以像素为单位。 | | x | 数字 | 绘制图像切片的 x 坐标。 | | y | 数字 | 绘制图像切片的 y 坐标。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
var myImage = document.getElementById('myImage');
myContext.drawImage(myImage, 10, 10, 50, 50, 0, 0);
清单 9-6 展示了如何将一幅图像加载到我们的基本画布模板中。
清单 9-6 。将图像加载到canvas元素中
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Create a new image element and fill it with a kitten.
var myImage = new Image();
myImage.src = 'http://lorempixel.com/g/200/200/cats';
// We can't do anything until the image has successfully loaded.
myImage.onload = function() {
myContext.drawImage(myImage, 0, 0);
};
</script>
</body>
</html>
这里,您只是将一个随机的占位符图像加载到画布中的位置(0, 0)。清单 9-7 展示了一个更复杂的图像操作。
清单 9-7 。使用画布操纵图像
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Create a new image element and fill it with a kitten.
var myImage = new Image();
myImage.src = 'http://lorempixel.com/g/300/300/cats';
// We can't do anything until the image has successfully loaded.
myImage.onload = function() {
myContext.drawImage(myImage, 25, 25, 150, 150, 0, 0, 150, 50);
};
</script>
</body>
</html>
这里你加载了一个 300 × 300 的占位符图像,但是从(25, 25)开始只截取了 75 × 75 的部分。然后你把这个切片渲染到canvas中,缩放到 150 × 50。
文本
2d 绘图上下文也可用于渲染文本。
fillText法
此方法使用当前填充样式从指定坐标开始填充画布上的指定文本。如果指定了可选的maxWidth参数,并且呈现的文本将超过该宽度,浏览器将尝试以这种方式呈现文本,使其适合指定的宽度(如果可用,使用压缩字体,使用较小的字体大小,等等)。).
语法
Context.fillText(textString, x, y, opt_maxWidth);
表 9-21。缩放图像时fillText方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 文字字串 | 线 | 文本字符串。 | | x | 数字 | 应该呈现文本的 x 坐标。 | | y | 数字 | 应该呈现文本的 y 坐标。 | | opt_maxWidth | 数字 | 最大宽度,以像素为单位。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.fillText('Hello world!', 10, 10, 200);
measureText法
此方法测量使用当前样式呈现指定文本时将产生的宽度。返回一个具有包含该值的width属性的TextMetrics对象。这为您提供了一种测试文本是否适合给定区域的方法,而无需实际呈现它。
语法
Context.measureText(textString);
表 9-22。缩放图像时measureText方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 文字字串 | 线 | 文本字符串。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
var textMetric = myContext.measureText('Hello world!');
var calculatedWidth = textMetric.width;
strokeText法
此方法使用当前笔画样式从指定坐标开始对画布上的指定文本进行笔画。如果指定了可选的maxWidth参数,并且呈现的文本将超过该宽度,浏览器将尝试以这种方式呈现文本,使其适合指定的宽度(如果可用,使用压缩字体,使用较小的字体大小,等等)。).
语法
Context.strokeText(textString, x, y, opt_maxWidth);
表 9-23。缩放图像时strokeText方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 文字字串 | 线 | 文本字符串。 | | x | 数字 | 应该呈现文本的 x 坐标。 | | y | 数字 | 应该呈现文本的 y 坐标。 | | opt_maxWidth | 数字 | 最大宽度,以像素为单位。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.strokeText('Hello world!', 10, 10, 200);
font属性
此属性定义文本呈现的字体。任何有效的 CSS 字体字符串都是允许的,但是请注意,用户必须在他们的系统上安装指定的字体。
语法
Context.font = CssFontString;
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.font = 'arial, helvetica, sans-serif';
textAlign属性
此属性定义文本呈现时的对齐方式。有效值为'left'、'right'、'center'、'start'和'end'。
语法
Context.textAlign = AlignValue;
表 9-24。textAlign属性的值
|
价值
|
说明
| | --- | --- | | 左边的 | 将文本左对齐。 | | 正确 | 将文本右对齐。 | | 中心 | 将文本居中。 | | 开始 | 在当前区域设置的起始端对齐文本(即,对于从左到右的语言,靠左对齐;对于从右到左的语言,靠右对齐)。这是默认值。 | | 目标 | 将文本在当前区域设置的末端对齐。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.textAlign = 'center';
textBaseline属性
该属性定义文本呈现时的基线。有效值为'alphabetic'、'bottom'、'hanging'、'ideographic'、'middle'和'top'。
语法
Context.textAlign = AlignValue;
表 9-25。textBaseline属性的值
|
价值
|
说明
| | --- | --- | | 字母的 | 对文本使用正常的字母基线。这是默认值。 | | 底部 | 基线是 em 正方形的底部。 | | 绞刑 | 文本使用悬挂基线。 | | 表意的 | 使用字符体的底部(假设它们突出于字母基线之下)。 | | 中间 | 文本基线位于 em 正方形的中间。 | | 顶端 | 文本基线是 em 正方形的顶部。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.textAlign = 'center';
清单 9-8 展示了如何使用文本命令渲染文本。
清单 9-8 。在画布中渲染文本
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.font = '35px sans-serif';
myContext.strokeStyle = '#000';
myContext.lineWidth = 2;
myContext.textAlign = 'center';
myContext.strokeText('Hello World', 100, 100);
</script>
</body>
</html>
阴影
canvas元素也可以根据其上绘制的元素来投射阴影。这通常用于文本,但也适用于形状和路径。如果你已经熟悉 CSS 阴影,画布阴影的参数将会非常熟悉。
shadowBlur房产
该属性定义模糊效果的大小。有效值为 0(无模糊,这是默认值)或任何正整数。
语法
Context.shadowBlur = ShadowBlurValue;
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.shadowBlur = 5;
shadowColor房产
这个属性定义了阴影的颜色。任何 CSS 颜色字符串都是有效值。默认为'rgba(0, 0, 0, 0)'。
语法
Context.shadowColor = CssColorValue;
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.shadowColor = '#00FF00';
shadowOffsetX房产
此属性定义阴影的 x 偏移。有效值可以是任何正整数或负整数,也可以是 0(默认值)。
语法
Context.shadowOffsetX = OffsetValue;
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.shadowOffsetX = 5;
shadowOffsetY房产
此属性定义阴影的 y 偏移。有效值可以是任何正整数或负整数,也可以是 0(默认值)。
语法
Context.shadowOffsetY = OffsetValue;
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.shadowOffsetY = 5;
清单 9-9 展示了在文本上创建一个阴影。
清单 9-9 。在画布中投射阴影
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Define a shadow.
myContext.shadowBlur = 2;
myContext.shadowColor = 'rgba(0, 100, 0, 0.5)';
myContext.shadowOffsetX = 5;
myContext.shadowOffsetY = 5;
myContext.font = '35px sans-serif';
myContext.strokeStyle = '#000';
myContext.lineWidth = 2;
myContext.textAlign = 'center';
myContext.strokeText('Hello World', 100, 100);
</script>
</body>
</html>
作文
每当您在画布上绘制新元素时,合成器都会查看画布上已经存在的内容。这个当前内容被称为目的地。新内容被称为源。然后合成器根据当前活动的合成器参照目的地绘制源。
globalCompositeOperation属性
此属性指定哪个合成器当前处于活动状态。
语法
Context.globalCompositeOperation = CompositorValue;
表 9-26。globalCompositeOperation属性的值
|
价值
|
说明
| | --- | --- | | 源-结束 | 在目标内容上绘制源内容。这是默认的合成器。 | | 源-顶部 | 源内容仅在与目标内容重叠的地方绘制。 | | 源入 | 仅在源内容和目标内容重叠的地方绘制源内容。其他一切都是透明的。 | | 源出 | 源内容仅在不与目标内容重叠的地方绘制。其他一切都是透明的。 | | 目的地完毕 | 源内容绘制在目标内容的下方。 | | 目的地-顶部 | 源内容只保存在与目标内容重叠的地方。目标内容绘制在源内容的下方。其他一切都是透明的。 | | 目的地 | 源内容只保存在与目标内容重叠的地方。其他一切都是透明的。 | | 目的地-出 | 源内容只保存在不与目标内容重叠的地方。其他一切都是透明的。 | | 复制 | 仅绘制目标内容。其他一切都是透明的。 | | 驳船 | 当目标内容和源内容重叠时,颜色是通过将两个内容的值相加来确定的。 | | 异或运算 | 目标内容正常呈现,除非它与源内容重叠,在这种情况下,两者都呈现为透明。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.globalCompositeOperation = 'source-atop';
第四章中的清单 4-16 提供了所有这些属性的动态示例。
剪辑
您可以将画布的绘制区域限制为您定义的任何闭合路径。这被称为削波。
clip法
此命令允许您基于当前路径创建一个剪辑区域。只有包含在剪辑区域内的内容才会显示。要重置剪辑区域,您可以执行以下三项操作之一:
- 您可以定义一个包含整个画布的路径,然后剪辑到该路径。
- 可以用不同的剪辑区域恢复到以前的绘图状态。这是最常见的解决方案。您可以在剪裁前保存绘图状态,然后在完成后恢复它。有关如何保存状态的详细信息,请参见后面的“保存和恢复画布状态”一节。
- 您可以通过调整大小来重置整个画布。
语法
Context.clip();
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.clip();
清单 9-10 演示了创建一个裁剪区域,并用它来裁剪一个正方形的角。
清单 9-10 。创建剪辑区域
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Create a circular clipping area.
myContext.beginPath();
myContext.arc(100, 100, 50, 0, 7);
myContext.clip();
// Draw a square in the canvas and fill it. Only the portion within the clipping
// area will be visible, so the corners will be cut off.
myContext.beginPath();
myContext.rect(60, 60, 80, 80);
myContext.fillStyle = 'black';
myContext.fill();
</script>
</body>
</html>
转换
2d 绘图上下文支持各种类型的转换。一旦设置了变换,它将应用于从该点开始渲染的所有内容。
translate法
该方法将画布的原点从当前位置移动到坐标指定的新位置。
语法
Context.translate(translateX, translateY);
表 9-27。缩放图像时translate方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 平移(translate) | 数字 | 原点的新 x 坐标。 | | 平移(translate) | 数字 | 原点的新 y 坐标。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.translate(10, 50);
rotate法
此方法将画布围绕原点顺时针旋转指定的角度(以弧度为单位)。
语法
Context.rotate(angle);
表 9-28。缩放图像时translate方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 角 | 数字 | 旋转角度,以弧度为单位。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.rotate(2);
scale法
该方法通过水平方向的scaleX和垂直方向的scaleY来缩放画布单元。
语法
Context.scale(scaleX, scaleY);
表 9-29。缩放图像时scale方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 横向缩放 | 数字 | x 轴的缩放量。 | | 数值 | 数字 | 缩放 y 轴的数量。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.translate(10, 50);
transform法
此方法允许您指定通用转换矩阵:
。
rotate、translate和scale简写方法都映射到转换矩阵,因此调用transform方法。例如,Context.translate(translateX, translateY)映射到Context.transform(1, 0, 0, 1, translateX, translateY),而Context.scale(scaleX, scaleY)映射到Context.transform(scaleX, 0, 0, scaleY, 0, 0)。
语法
Context.transform(scaleX, skewX, skewY, scaleY, translateX, translateY);
表 9-30。bezierCurveTo方法的参数
|
参数
|
类型
|
说明
| | --- | --- | --- | | 横向缩放 | 数字 | x 轴的缩放量。 | | skewX | 数字 | x 轴的倾斜量。 | | 歪斜 | 数字 | y 轴的倾斜量。 | | 数值 | 数字 | 缩放 y 轴的数量。 | | 平移(translate) | 数字 | 新原点的 x 坐标。 | | 平移(translate) | 数字 | 新原点的 y 坐标。 |
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Reset all transformations.
myContext.transform(0, 0, 0, 0, 0, 0);
清单 9-11 演示了如何使用scale和translate转换。
清单 9-11 。使用scale和translate变换
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
/**
* Draws a 100x100 square at (0, 0) in the specified color. Indicates the origin
* corner with a small black square.
* @param {string} color A valid CSS color string.
*/
function drawSquare(color) {
myContext.fillStyle = color;
myContext.beginPath();
myContext.rect(0, 0, 100, 100);
myContext.fill();
myContext.fillStyle = '#000';
myContext.beginPath();
myContext.rect(0, 0, 5, 5);
myContext.fill();
}
// Draw a square, fill it with red.
drawSquare('rgba(255, 0, 0, 0.5)');
// Translate the canvas.
myContext.translate(20, 40);
// Scale the canvas.
myContext.scale(1, 1.5);
// Draw the same square again, fill it with blue.
drawSquare('rgba(0, 0, 255, 0.5)');
// Translate the canvas again.
myContext.translate(50, -20);
// Scale the canvas again.
myContext.scale(1.5, 1);
// Draw the same square again, fill it with green.
drawSquare('rgba(0, 255, 0, 0.5)');
</script>
</body>
</html>
保存和恢复画布状态
2d 绘图环境包括一个基本状态管理系统。给定状态由上下文中的以下属性组成:
globalAlpha的当前值- 电流
strokeStyle和fillStyle lineCap, lineJoin, lineWidth和miterLimit中的当前线路设置shadowBlur, shadowColor, shadowOffsetX和shadowOffsetY中的当前阴影设置- 在
globalCompositeOperation中设置的当前合成操作 - 当前剪辑路径
- 已应用于绘图上下文的任何转换
状态保存在后进先出堆栈中,因此您保存的最后一个状态将是第一个可供检索的状态。没有办法在堆栈中跳来跳去。
save法
该命令将当前上下文保存到堆栈中。
语法
Context.save();
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Saves an initial "blank" canvas state before anything has been drawn or set.
myContext.save();
restore法
该命令从堆栈中删除最近存储的状态,并将其恢复到上下文中。
语法
Context.restore();
例如
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Saves an initial "blank" canvas state before anything has been drawn or set.
myContext.restore();
清单 9-12 展示了保存和恢复状态。
清单 9-12 。保存和恢复工程图上下文状态
<!DOCTYPE html>
<html>
<head>
<title>The HTML5 Programmer's Reference</title>
<style>
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="210">Did You Know: Every time
you use a browser that doesn't support HTML5, somewhere a kitten
cries. Be nice to kittens, upgrade your browser!
</canvas>
<script>
// Get the context we will be using for drawing.
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
// Create an array of colors to load into the stack.
var allTheColors = ['#ff0000', '#ff8800', '#ffff00', '#00ff00', '#0000ff',
'#4b0082', '#8f00ff'];
// Load the colors and stroke style into the stack.
for (var i = 0; i < allTheColors.length; i++) {
myContext.strokeStyle = allTheColors[i];
myContext.lineWidth = 30;
myContext.save();
}
// Restore colors from the stack and draw.
for (var i = 0; i < 8; i++) {
myContext.restore();
myContext.beginPath();
myContext.moveTo(0, ((30 * i) + 15));
myContext.lineTo(200, ((30 * i) + 15));
myContext.stroke();
}
</script>
</body>
</html>