Open jtwang7 opened 3 years ago
参考文章:
ctx.drawImage()
canvas 将图片绘制到画布上,就是依靠 ctx 上下文对象的 drawImage() 方法实现的。 参考:HTML5 canvas drawImage() 方法 可以知道它的一些基本用法
drawImage()
方法在画布上绘制图像、画布或视频。drawImage()
方法也能够绘制图像的某些部分,以及/或者增加或减少图像的尺寸。JavaScript 语法 1
在画布上定位图像:
context.drawImage(img,x,y);
JavaScript 语法 2
在画布上定位图像,并规定图像的宽度和高度:
context.drawImage(img,x,y,width,height);
JavaScript 语法 3
剪切图像,并在画布上定位被剪切的部分:
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
参数 | 描述 |
---|---|
img | 规定要使用的图像、画布或视频。 |
sx | 可选。开始剪切的 x 坐标位置。 |
sy | 可选。开始剪切的 y 坐标位置。 |
swidth | 可选。被剪切图像的宽度。 |
sheight | 可选。被剪切图像的高度。 |
x | 在画布上放置图像的 x 坐标位置。 |
y | 在画布上放置图像的 y 坐标位置。 |
width | 可选。要使用的图像的宽度。(伸展或缩小图像) |
height | 可选。要使用的图像的高度。(伸展或缩小图像) |
在 html 里图片的加载时是异步的。(设置src本身是同步的,但是浏览器下载和显示图片是异步的。) 因此,在资源还没有加载完成的时候就执行了 drawImage,所以无法成功加载到画布当中。 为了解决图片异步加载的问题,我们通过添加一个 onload 事件,并将 drawImage 作为它的回调函数,等待图片加载完成后自动执行回调。
onload 事件会在页面或图像加载完成后立即发生。
<canvas id='mycanvas' width="500" height="500"></canvas>
<script type="text/javascript">
window.onload = function(){
// 创建画布
let mycanvas = document.getElementById('mycanvas')
let ctx = mycanvas.getContext('2d')
// 创建 Image 实例
let img = new Image();
img.onload = function(){
// 等待图片异步加载完成后,执行绘制操作
ctx.drawImage(img,100,100);
}
// 加载图片源
img.src = "https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1537549551&di=3f8d4d76679adcae225387f7d6b199aa&src=http://gss0.baidu.com/-4o3dSag_xI4khGko9WTAnF6hhy/lvpics/h=800/sign=b49dc48f8718367ab28972dd1e728b68/9922720e0cf3d7ca7f0736d0f31fbe096a63a9a6.jpg";
}
</script>
参考:HTMLCanvasElement.toDataURL()
Canvas可以导出为图片的方法有以下几种: ✅ toDataURL():该方法可以将Canvas内容导出为一张Base64编码格式的图片。示例代码如下:
var canvas = document.getElementById('myCanvas');
var image = canvas.toDataURL("image/png");
✅ toBlob():该方法可以将Canvas内容导出为Blob对象。示例代码如下:
var canvas = document.getElementById('myCanvas');
canvas.toBlob(function(blob) {
// 将blob对象转换成URL
var url = URL.createObjectURL(blob);
// 创建一个img标签显示图片
var img = document.createElement('img');
img.src = url;
document.body.appendChild(img);
});
✅ drawImage():该方法可以将Canvas内容绘制到一个img标签或者另一个Canvas中,实现导出为图片的效果。示例代码如下:
var canvas = document.getElementById('myCanvas');
var img = new Image();
img.src = canvas.toDataURL("image/png");
// 将Canvas内容绘制到一个img标签中
document.body.appendChild(img);
✅ toDataURLHD():该方法可以将Canvas内容导出为高清晰度的图片,适用于高分辨率屏幕。示例代码如下:
var canvas = document.getElementById('myCanvas');
var image = canvas.toDataURLHD("image/png");
toDataURL()
简介HTMLCanvasElement.toDataURL() 方法返回一个包含图片展示的 data URI。可以使用 type 参数指定其类型,默认为 PNG 格式。图片的分辨率为96dpi。
canvas.toDataURL(type, encoderOptions);
参数:
返回值: 包含 data URI 的DOMString
toBlob()
简介canvas.toBlob()
方法是在 HTML5 中提供的 Canvas API 的一部分,它允许将 Canvas 元素的内容保存为一个 Blob 对象。Blob 对象是二进制数据的容器,它通常用于将数据发送到服务器或在客户端进行本地存储。
相较于
toDataURL()
方法,blob 对象的存储体积更小,可以有效避免图片较大时 toDataURL 生成的 base64 文件路径过长,超出浏览器限制,导致无法下载的问题。
以下是使用 canvas.toBlob() 方法的示例代码:
var canvas = document.getElementById("myCanvas");
canvas.toBlob(function(blob) {
// 处理 Blob 对象
var url = URL.createObjectURL(blob);
// 将 URL 分配给图像元素
var img = document.createElement("img");
img.src = url;
document.body.appendChild(img);
}, "image/jpeg", 0.95);
第一个参数是一个回调函数:它接收一个 Blob 对象作为参数。在回调函数中,可以对 Blob 对象进行操作,例如将其发送到服务器或将其用作图像元素的源。
第二个参数是输出格式的 MIME 类型。在上面的示例中,我们将输出格式设置为 JPEG 格式。
第三个参数是输出图像质量,它的值范围从 0 到 1。在上面的示例中,我们将输出图像质量设置为 0.95,这意味着输出图像的质量较高。
为了将 canvas 保存为图片地址,我们需要获取到 canvas 实例对象,通常我们只需要通过 document.querySelector()
等 DOM 元素获取方法获取 canvas 对象即可,但是 webgl 类型的 canvas 需要做一步特殊的处理:
let canvas = document.querySelector('xxx'); // 获取 canvas 实例对象
let webgl = canvas.getContext("experimental-webgl", {preserveDrawingBuffer: true}); // 修改 canvas 对象的上下文
let imgUrl = webgl.canvas.toDataURL('image/webgl'); // 调用修改后的 canvas.toDataURL 方法
这么做的原因是因为: webgl canvas 的 preserveDrawingBuffer 默认值为 false (WebGLRenderer),它的 bool 值决定了是否保留绘图缓冲区,默认是不保留,这就导致完成 webgl canvas 绘图后,我们获取不到画布信息,转出来的 image url 自然就变成了一个空白图片。因此我们需要在上下文中修改该属性值,然后再重新获取 canvas 实例对象转为 url 形式。
preserveDrawingBuffer
属性的详细解答I know this has been answered elsewhere but I can't find it so ....
preserveDrawingBuffer: false
means WebGL can swap buffers instead of copy buffers.
WebGL canvases have 2 buffers. The one you're drawing to and the one being displayed. When it comes time to draw the webpage WebGL has 2 options
Copy the drawing buffer to the display buffer.
This operation is slower obviously as copying thousands or millions pixels is not a free operation
Swap the two buffers.
This operation is effectively instant as nothing really needs to happen except to swap the contents of 2 variables.
Whether WebGL swaps or copies is up to the browser and various other settings but if preserveDrawingBuffer is false WebGL can swap, if it's true it can't.
If you'd like to see a perf difference I'd suggested trying your app on mobile phone. Make sure antialiasing is off too since antialiasing requires a resolve step which is effectively copy operation.
当使用 canvas 元素的 toDataURL() 方法导出图片时,可能会出现导出的图片是空白的情况。这通常是由于以下原因之一导致的:
如果您无法解决这个问题,您可以尝试使用其他工具来导出 canvas 元素的内容,例如使用 html2canvas 库,这个库可以将整个 DOM 元素渲染为图片,并导出为 data URL 或者 blob 格式的图片。
浏览器对于 WebGL Context 上下文存在一定的数量限制,当一个页面中 WebGL Context 上下文数量过多时,浏览器会按先进先出的顺序丢失上下文信息,我们可以将 WebGL 上下文信息导出为图片展示,同时销毁较早的 WebGL Context 避免意外丢失的情况。
本示例以 deck.gl + mapbox
第三方地图库为例,生成 WebGL Context 模拟问题场景。
export default function Map({ ods }: { ods: any[] }) {
// ......
const mapboxRef = useRef<MapRef>(null!);
// 保存 deckgl 的 canvas 对象
const deckglCanvas = useRef<HTMLCanvasElement>(null!);
// 将不同 canvas 对象绘制到同一 canvas 对象上,并导出 url
function canvasClone(canvasElements: HTMLCanvasElement[]) {
const canvas = document.createElement("canvas");
canvas.width = _.max(canvasElements.map((c) => c.width))!;
canvas.height = _.max(canvasElements.map((c) => c.height))!;
const ctx = canvas.getContext("2d");
if (ctx) {
for (const cloneTraget of canvasElements) {
ctx.globalAlpha = 1;
ctx.drawImage(cloneTraget, 0, 0);
}
}
const url = canvas.toDataURL("image/png");
return url;
}
const onMapboxLoad = () => {
// mapbox 实例
const instance = mapboxRef.current.getMap();
// webgl 保存为 image 展示并销毁 webgl context
setTimeout(() => {
const url = canvasClone([
mapboxRef.current.getCanvas(), // 🔥
deckglCanvas.current,
]);
setURL(url);
}, 500);
};
// layers
const arcUid = useId();
const arclayer = useMemo(() => {
return new ArcLayer({
id: arcUid,
data: ods,
pickable: true,
getWidth: 1,
greatCircle: true,
getSourcePosition: (d) => d.from.coordinates,
getTargetPosition: (d) => d.to.coordinates,
getSourceColor: (d) => [244, 164, 158],
getTargetColor: (d) => [255, 101, 0],
});
}, [arcUid, ods]);
const deckglUid = useId();
// image-url lists
const [url, setURL] = useState<string | undefined>(undefined);
return !url ? (
<DeckGL
id={deckglUid}
glOptions={{ preserveDrawingBuffer: true }} // 🔥
initialViewState={INITIAL_VIEW_STATE}
viewState={viewState}
layers={[scatterplotlayer, arclayer]}
width={width}
height={height}
style={{ position: "relative" }}
controller={true}
onAfterRender={({ gl }) => {
deckglCanvas.current = gl.canvas as HTMLCanvasElement; // 🔥
}}
>
<StaticMap
ref={mapboxRef}
preserveDrawingBuffer={true} // 🔥
mapboxAccessToken={mapboxAccessToken}
mapStyle="mapbox://styles/mapbox/light-v11"
onLoad={onMapboxLoad}
/>
</DeckGL>
) : (
<img
alt="OD弧线图"
src={url}
style={{ position: "relative", width, height }}
/>
);
}
确保 WebGL Context 上下文中 preserveDrawingBuffer
属性开启
具体原因见 关于 webgl preserveDrawingBuffer 属性的详细解答
// webgl context - options xxx.getContext( 'webgl' , { preserveDrawingBuffer: true })
在本例中,
deckgl
和mapbox
对preserveDrawingBuffer
属性进行了不同方式的封装,因此具体配置需根据官网进行调整。
尽量基于第三方库正确的获取对应的 canvas 对象
本例中 deckgl
和 mapbox
均有对应的 canvas 对象获取方法,若第三方库暴露了相应的获取方法,则应尽量使用这些方法,避免直接使用 getElementById
等方式获取 canvas 对象,因为该方法获取的 canvas 对象可能并不完全或者过时。
canvas 对象合并
function canvasClone(canvasElements: HTMLCanvasElement[]) {
const canvas = document.createElement("canvas");
canvas.width = _.max(canvasElements.map((c) => c.width))!;
canvas.height = _.max(canvasElements.map((c) => c.height))!;
const ctx = canvas.getContext("2d");
if (ctx) {
for (const cloneTraget of canvasElements) {
ctx.globalAlpha = 1;
ctx.drawImage(cloneTraget, 0, 0);
}
}
const url = canvas.toDataURL("image/png");
return url;
}
当你遇到 Canvas 绘制模糊的问题时,或许你可以看看这篇文章~ 🥳
在高清显示屏出现之前,比如屏幕宽度为1000px 那么其宽度上的物理像素也是1000px,而在高清屏出现之后,屏幕宽度为 1000px 时,物理像素有可能达到 2000px 或者更高。为了方便查询物理像素和屏幕像素的比值,在 window 对象上增加了一个属性 devicePixelRatio
来表示这个比值。
比如在 devicePixelRatio
为2的设备上,当我们使用 CSS 绘制一条 1px 的线时,为了保证绘制的大小,物理像素实际上会使用 2px 来绘制这一条线,而这样的转换是浏览器自动处理的,所以对开发者来说并没有太大的困扰。
那么上面既然说了浏览器在渲染的时候会自动处理像素比的问题,CSS 绘制的图像经过转换之后不会出现模糊的问题,但 canvas 上怎么就出现了呢?
因为在 canvas 标签上定义的 width 和 height 的值并不会被转换,100px 就会被渲染成 100px 的物理像素,但是设备要求的是 200px,这时浏览器只能智能地填充像素之间的空白,以适应要求的大小。这就是 canvas 绘制的图片出现模糊的原因。
function createHDCanvas (canvas, target, w, h) {
const ratio = window.devicePixelRatio || 1;
canvas.width = w * ratio; // 实际渲染像素
canvas.height = h * ratio; // 实际渲染像素
canvas.style.width = `${w}px`; // 控制显示大小
canvas.style.height = `${h}px`; // 控制显示大小
const ctx = canvas.getContext('2d');
// 绘制 canvas: 注意此时画布宽高是 w * ratio, h * ratio。
// 其中 target 是外部 canvas 或 image,将其覆盖到当前 canvas 上。
// canvas 通常是一个空容器,用于承载 target 这个实际目标。
ctx.drawImage(target, 0, 0, w * ratio, h * ratio)
// 缩放尺寸
ctx.scale(ratio, ratio)
// canvas 绘制
return canvas;
}
🌈 CanvasRenderingContext2D.scale()
是 Canvas 2D API 根据 x 水平方向和 y 垂直方向,为 canvas 单位添加缩放变换的方法:
默认的,在 canvas 中一个单位实际上就是一个像素。例如,如果我们将 0.5 作为缩放因子,最终的单位会变成 0.5 像素,并且形状的尺寸会变成原来的一半。相似的方式,我们将 2.0 作为缩放因子,将会增大单位尺寸变成两个像素。形状的尺寸将会变成原来的两倍。
对应示例中 ctx.scale(ratio, ratio)
的含义就是:将 canvas 画布的像素尺寸扩大 ratio 倍。
【canvas 画布尺寸和样式尺寸是一致的,不存在显示像素与物理像素不一致的情况,在 canvas 中一个单位实际上就是一个像素,所以 scale 缩放同时影响这两个尺寸不难理解】
由于我们将 canvas 初始画布尺寸设置为了元素尺寸设置 ratio 倍,因此将 canvas 放大后,确保了元素尺寸和画布尺寸一致,画布中的内容完全展示。若不调用 scale
缩放方法,canvas 只能展示部分的绘图内容。
🔥 上述方法实际绘制的元素尺寸被扩大了 ratio 倍,图像展示仍是模糊的,我们还需要用原来的尺寸去加载当前图像,相当于变相对图像进行了压缩,此时图像大小为初定元素尺寸(物理像素),显示像素则为原来的两倍(2 * 元素尺寸)。
Pixi.js
解决方案const app = new PIXI.Application({
// ......
resolution: 2, // 👉 设置像素比
autoDensity: true, // 👉 自适应尺寸大小
});
Canvas导出图片模糊的问题通常是由于导出的图片分辨率低于实际画布分辨率的情况。Canvas实际上是基于像素的画布,如果导出的图片分辨率低于实际画布分辨率,那么就会导致图片模糊。
解决方法包括:
提高导出图片的分辨率:可以通过调整导出图片的分辨率来解决模糊的问题。例如,可以将导出图片的宽度和高度设置为画布实际宽度和高度的两倍或更高。
确保画布分辨率和导出图片分辨率一致:在导出图片之前,可以将画布的分辨率设置为导出图片的分辨率,以确保导出的图片与实际画布分辨率一致。
使用CSS Scale:使用CSS Scale来调整画布大小以达到导出图片的分辨率。例如,如果画布大小是300x300,但需要导出600x600的图片,可以将画布的CSS Scale设置为2,以使画布在导出时变为600x600。
使用高清Canvas库:如果以上方法不能解决问题,可以尝试使用高清Canvas库,这些库可以自动处理分辨率问题,以确保导出的图片保持清晰。例如,可以尝试使用Retina.js或HiDPI-Canvas。
假设我们现在 canvas 和 css 的大小都是 10 * 10,那么 canvas 画完的照片中就会有 100 个(像素)点,也就是只有 100 个点的信息;但是到了高清屏中(如 dpr = 2),我们需要 400 个点的信息,原来的点不够用怎么办?于是就会有一套算法来自动生成这些点的信息,从而造成了模糊。那应该怎么办呢🤔?我们需要更多的点,所以可以这样子搞,把画布放大 dpr 倍,也就是把 canvas 变大 dpr 倍,而 css 的大小保持不变,虽然 canvas 变大了,但是最终在页面上绘制的时候放到 css 中又会因为等比缩放(上面第一点说到的原因)变回来了原来大小,这样一折腾,点就变多了。但是要注意什么呢,画布变大了,相应的绘制操作(画圆、画矩形等)也需要相应放大,一般有两种方法:
✅ 方法一
// 放大画布之后,直接用 scale 放大整个坐标系
// 但是你要知道我们一直是在放大的坐标系上绘制的,可能不知道什么时候(比如重新设置画布宽高),scale 可能就会被重置成 1 了,从而造成画面错乱
adaptDPR() { // 在初始化 canvas 的时候就要调用该方法
const dpr = window.devicePixelRatio;
const { width, height } = this.canvas;
// 重新设置 canvas 自身宽高大小和 css 大小。放大 canvas;css 保持不变,因为我们需要那么多的点
this.canvas.width = Math.round(width * dpr);
this.canvas.height = Math.round(height * dpr);
this.canvas.style.width = width + 'px';
this.canvas.style.height = height + 'px';
// 直接用 scale 放大整个坐标系,相对来说就是放大了每个绘制操作
this.ctx2d.scale(dpr, dpr);
// 接下来的绘制操作和往常一样,比如画个矩形 ctx2d.strokeRect(x, y, w, h);原来该怎么算就怎么算,该怎么调用还是怎么调用
}
✅ 方法二
// 放大画布之后,需要把每一个绘制的 api 都乘以 dpr
// * 这样一来使用的时候就会很麻烦,所以我们需要把所有的绘制操作进行统一封装
// 可以参考这个库:https://github.com/jondavidjohn/hidpi-canvas-polyfill,不过这个库也不是所有 api 都覆盖
adaptDPR() { // 在初始化 canvas 的时候就要调用该方法
const dpr = window.devicePixelRatio;
const { width, height } = this.canvas;
// 重新设置 canvas 自身宽高大小和 css 大小。放大 canvas;css 保持不变,因为我们需要那么多的点
this.canvas.width = Math.round(width * dpr);
this.canvas.height = Math.round(height * dpr);
this.canvas.style.width = width + 'px';
this.canvas.style.height = height + 'px';
// 注意这里没有用 scale
}
// 接下来在每个涉及绘制的 api 时都乘以 dpr,比如绘制矩形的时候
strokeRect(x: number, y: number, w: number, h: number) {
const { ctx2d, dpr } = this;
if (!ctx2d) return;
x = x * dpr;
y = y * dpr;
w = w * dpr;
h = h * dpr;
ctx2d.strokeRect(x, y, w, h);
}
基于 Canvas 的浏览器图片下载方法
利用 Canvas 将图片转为 base64 地址,创建 a
标签下载图片地址。
存在的问题:图片体积过大时,转成的 base64 url 地址字符串过长,可能会超出浏览器限制的字符串最大长度而被截断,从而下载失败。 解决方法:转用
toBlob()
生成 blob 对象
function getImageDataURL(image) {
// 创建画布
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext('2d');
// 以图片为背景剪裁画布
ctx.drawImage(image, 0, 0, image.width, image.height);
return canvas.toDataURL('image/png', 1);
}
function downLoad(downloadName, url) {
const tag = document.createElement('a');
tag.download = downloadName // download 属性值是最终下载得到的图片文件的文件名
const image = new Image();
image.src = url;
// 🔥 设置 crossOrigin 属性,否则图片跨域会报错
image.setAttribute('crossOrigin', 'Anonymous');
// 等待图片加载完成再下载资源
image.addEventListner('load', () => {
tag.href = getImageDataURL(image); // 关联图片链接
tag.click(); // 触发点击
})
}
function getImageDataURL(image) {
return canvas.toDataURL('image/png', 1);
}
function downLoad(downloadName, url) {
const tag = document.createElement('a');
tag.download = downloadName // download 属性值是最终下载得到的图片文件的文件名
const image = new Image();
image.src = url;
// 🔥 设置 crossOrigin 属性,否则图片跨域会报错
image.setAttribute('crossOrigin', 'Anonymous');
// 等待图片加载完成再下载资源
image.addEventListner('load', () => {
// 创建画布
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext('2d');
// 以图片为背景剪裁画布
ctx.drawImage(image, 0, 0, image.width, image.height);
// 生成 Blob 对象实例
canvas.toBlob((blob) => {
tag.href = URL.createObjectURL(blob!);
tag.click();
});
})
}
canvas 绘制
参考:
canvas 画布
html 通过标签
<canvas />
创建一个画布,浏览器可以在该<canvas />
画布元素上绘图。id 属性一般是必要的,因为后续我们会通过 id 来获取该 DOM 节点。
获取绘图上下文
要在画布上绘制图形,第一步先获取绘图上下文: 通过调用 canvas DOM 元素的
getContext()
方法,我们可以获取 canvas 元素的绘图上下文引用。对于平面图形,需要给方法传入参数 "2d",此时我们获取的就是 2D 的绘图上下文。描边 & 填充
描边:为图形边界着色,对应属性 strokeStyle,属性值可以时字符串,渐变对象或者图案对象。
填充:为形状自动填充指定样式,对应 fillStyle 属性,样式可以是颜色、渐变或图像。
strokeStyle 和 fillStyle 直属于 ctx 上下文对象的属性,因此后续所有在该画布上下文中绘制的图形,都会使用这两种描边和填充样式,除非再次修改。
绘制矩形
矩形是 canvas 唯一一个直接提供的形状绘制方式。canvas 绘图上下文提供了相关的三个方法:
context.fillRect(x, y, w, h)
:在画布上绘制并自动填充矩形,填充颜色用 fillStyle 属性指定。clearRect()
context.clearRect()
用于清除画布某个区域,这个方法在某些时候特别重要。 首先,我们要知道:在 canvas 画布中绘制的图形是永久保留的,如此强调这一点是因为,若要实现一个物体的移动效果,单纯改变绘制的坐标是行不通的,如下:上述效果会保留所有绘制的矩形,因此最终会展示出来一连串的矩形。我们需要在下一次绘制矩形时,清除上一次的绘制,最简单的方法就是在下一次绘制时,清空整个画布区域(前提时该画布中没有其他需要保留的图形)。
绘制路径
canvas 只提供了绘制矩形的方法,若想要绘制更加复杂的图形或形状,就需要调用 2D 绘图上下文的路径绘制。 路径绘制方法:
context.beginPath()
:表示开始绘制新的路径。context.arc(x, y, radius, startAngle, endAngle, counterclockwise)
:以坐标(x, y) 为圆心,radius 为半径画一条弧线,起始角度 startAngle,结束角度 endAngle (单位均为弧度),counterclockwise 表示是否逆时针计算起始角度和结束角度(默认顺时针)context.arcTo(x1, y1, x2, y2, radius)
:以给定半径 radius,从上一点开始,绘制一条经过 (x1, y1) 到 (x2, y2) 的弧线。context.quadraticCurveTo(cx, cy, x, y)
:以 (cx, cy) 为控制点,绘制一条从上一点到 (x, y) 的弧线(二次贝塞尔曲线)context.bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
:以 (c1x, c1y) 和 (c2x, c2y) 为控制点,绘制一条从上一点到 (x, y) 的弧线 (三次贝塞尔曲线)context.lineTo(x, y)
:绘制一条从上一点到 (x, y) 的直线context.moveTo(x, y)
:不绘制线条,只把绘制光标移动到 (x, y),即可以调整“上一点”的位置context.rect(x, y, width, height)
:以给定宽度和高度在 (x, y) 绘制一个矩形。该方法与矩形绘制相比,区别在于该方法创建的是一条路径,不是独立的图形。路径绘制完成后,canvas 还提供了额外的操作路径方法:
context.closePath()
:绘制一条返回起点的线,即闭合路径。context.fill()
:填充(闭合)路径,填充颜色通过 fillStyle 属性指定。context.stroke()
:描画路径,轮廓颜色通过 strokeStyle 属性指定。context.clip()
:基于已有路径创建一个剪切区域。