H5端API库,为Taro跨端开发框架提供Web/H5端的API实现
—
Canvas drawing and manipulation APIs providing basic HTML5 Canvas operations with Mini Program compatibility for 2D graphics and image processing.
Create and manage canvas contexts for drawing operations.
/**
* Create canvas context for drawing operations
* @param canvasId - Canvas element ID
* @param componentInstance - Component instance (optional in H5)
* @returns Canvas rendering context
*/
function createCanvasContext(canvasId: string, componentInstance?: any): CanvasContext;
interface CanvasContext {
// Drawing operations
fillRect(x: number, y: number, width: number, height: number): void;
strokeRect(x: number, y: number, width: number, height: number): void;
clearRect(x: number, y: number, width: number, height: number): void;
// Path operations
beginPath(): void;
closePath(): void;
moveTo(x: number, y: number): void;
lineTo(x: number, y: number): void;
arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
// Styles
setFillStyle(color: string): void;
setStrokeStyle(color: string): void;
setLineWidth(lineWidth: number): void;
// Text
fillText(text: string, x: number, y: number, maxWidth?: number): void;
strokeText(text: string, x: number, y: number, maxWidth?: number): void;
setFontSize(fontSize: number): void;
// Images
drawImage(imageResource: string, x: number, y: number): void;
drawImage(imageResource: string, x: number, y: number, width: number, height: number): void;
// Execute drawing
draw(reserve?: boolean, callback?: () => void): void;
}Extract and manipulate image data from canvas elements.
/**
* Convert canvas content to temporary file path
* @param options - Canvas export configuration
* @returns Promise resolving to temporary file path
*/
function canvasToTempFilePath(options: CanvasToTempFilePathOption): Promise<CanvasToTempFilePathResult>;
/**
* Get image data from canvas
* @param options - Image data retrieval configuration
* @returns Promise resolving to image data
*/
function canvasGetImageData(options: CanvasGetImageDataOption): Promise<CanvasGetImageDataResult>;
/**
* Put image data to canvas
* @param options - Image data insertion configuration
* @returns Promise that resolves when data is inserted
*/
function canvasPutImageData(options: CanvasPutImageDataOption): Promise<void>;
interface CanvasToTempFilePathOption extends CallbackOptions {
/** Canvas element ID */
canvasId: string;
/** Image file type (default: 'png') */
fileType?: 'jpg' | 'png';
/** Image quality (0-1, for jpg only) */
quality?: number;
/** Export width (default: canvas width) */
destWidth?: number;
/** Export height (default: canvas height) */
destHeight?: number;
}
interface CanvasToTempFilePathResult {
/** Temporary file path */
tempFilePath: string;
}
interface CanvasGetImageDataOption extends CallbackOptions {
/** Canvas element ID */
canvasId: string;
/** Start x coordinate */
x: number;
/** Start y coordinate */
y: number;
/** Width of image data area */
width: number;
/** Height of image data area */
height: number;
}
interface CanvasGetImageDataResult {
/** Image data array */
data: Uint8ClampedArray;
/** Image width */
width: number;
/** Image height */
height: number;
}
interface CanvasPutImageDataOption extends CallbackOptions {
/** Canvas element ID */
canvasId: string;
/** Image data array */
data: Uint8ClampedArray;
/** Start x coordinate */
x: number;
/** Start y coordinate */
y: number;
/** Image width */
width: number;
/** Image height */
height: number;
}Usage Examples:
import {
createCanvasContext,
canvasToTempFilePath,
canvasGetImageData,
canvasPutImageData
} from "@tarojs/taro-h5";
// Basic canvas drawing
function drawOnCanvas() {
const ctx = createCanvasContext('myCanvas');
// Set styles
ctx.setFillStyle('#ff0000');
ctx.setStrokeStyle('#00ff00');
ctx.setLineWidth(2);
// Draw shapes
ctx.fillRect(10, 10, 100, 100);
ctx.strokeRect(120, 10, 100, 100);
// Draw circle
ctx.beginPath();
ctx.arc(75, 200, 50, 0, 2 * Math.PI);
ctx.setFillStyle('#0000ff');
ctx.fill();
// Draw text
ctx.setFontSize(20);
ctx.setFillStyle('#000000');
ctx.fillText('Hello Canvas', 10, 300);
// Execute drawing
ctx.draw();
}
// Export canvas as image
async function exportCanvas() {
try {
const result = await canvasToTempFilePath({
canvasId: 'myCanvas',
fileType: 'png',
quality: 1.0
});
console.log('Canvas exported to:', result.tempFilePath);
return result.tempFilePath;
} catch (error) {
console.error('Canvas export failed:', error);
}
}
// Image data manipulation
async function manipulateImageData() {
try {
// Get image data
const imageData = await canvasGetImageData({
canvasId: 'myCanvas',
x: 0,
y: 0,
width: 300,
height: 300
});
// Modify pixel data (invert colors)
const data = new Uint8ClampedArray(imageData.data);
for (let i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // Red
data[i + 1] = 255 - data[i + 1]; // Green
data[i + 2] = 255 - data[i + 2]; // Blue
// Alpha channel (i + 3) unchanged
}
// Put modified data back
await canvasPutImageData({
canvasId: 'myCanvas',
data: data,
x: 0,
y: 0,
width: imageData.width,
height: imageData.height
});
console.log('Image data modified successfully');
} catch (error) {
console.error('Image data manipulation failed:', error);
}
}The following canvas APIs are not available in the H5 environment:
// ❌ Not implemented - Advanced canvas features
declare function createOffscreenCanvas(): never;Note: createOffscreenCanvas is not supported in the H5 environment due to browser compatibility limitations. Use regular canvas elements with createCanvasContext instead.
Complex canvas operations and optimization techniques.
// Canvas drawing manager
class CanvasManager {
private context: CanvasContext;
private canvasId: string;
constructor(canvasId: string) {
this.canvasId = canvasId;
this.context = createCanvasContext(canvasId);
}
// Batch drawing operations
batchDraw(operations: (() => void)[], reserve = false): Promise<void> {
return new Promise((resolve) => {
operations.forEach(op => op());
this.context.draw(reserve, () => resolve());
});
}
// Draw image with error handling
async drawImageSafe(imageSrc: string, x: number, y: number, width?: number, height?: number): Promise<boolean> {
return new Promise((resolve) => {
try {
if (width !== undefined && height !== undefined) {
this.context.drawImage(imageSrc, x, y, width, height);
} else {
this.context.drawImage(imageSrc, x, y);
}
this.context.draw(false, () => resolve(true));
} catch (error) {
console.error('Failed to draw image:', error);
resolve(false);
}
});
}
// Clear canvas
clear(width: number, height: number): Promise<void> {
return new Promise((resolve) => {
this.context.clearRect(0, 0, width, height);
this.context.draw(false, () => resolve());
});
}
// Export canvas
async exportAsImage(options: Partial<CanvasToTempFilePathOption> = {}): Promise<string | null> {
try {
const result = await canvasToTempFilePath({
canvasId: this.canvasId,
fileType: 'png',
quality: 1.0,
...options
});
return result.tempFilePath;
} catch (error) {
console.error('Canvas export failed:', error);
return null;
}
}
}
// Usage
const canvasManager = new CanvasManager('drawingCanvas');
// Batch drawing
await canvasManager.batchDraw([
() => {
canvasManager.context.setFillStyle('#ff0000');
canvasManager.context.fillRect(0, 0, 100, 100);
},
() => {
canvasManager.context.setFillStyle('#00ff00');
canvasManager.context.fillRect(100, 0, 100, 100);
}
]);
// Safe image drawing
const success = await canvasManager.drawImageSafe('/path/to/image.png', 50, 50, 200, 200);
if (success) {
console.log('Image drawn successfully');
}Best practices for canvas performance in web environments.
// Optimized canvas operations
class OptimizedCanvas {
private context: CanvasContext;
private operations: (() => void)[] = [];
private drawPending = false;
constructor(canvasId: string) {
this.context = createCanvasContext(canvasId);
}
// Queue operations for batch execution
queueOperation(operation: () => void): void {
this.operations.push(operation);
this.scheduleDraw();
}
private scheduleDraw(): void {
if (this.drawPending) return;
this.drawPending = true;
requestAnimationFrame(() => {
// Execute all queued operations
this.operations.forEach(op => op());
this.operations = [];
// Single draw call
this.context.draw();
this.drawPending = false;
});
}
// Immediate drawing (use sparingly)
drawImmediate(operation: () => void): Promise<void> {
return new Promise((resolve) => {
operation();
this.context.draw(false, () => resolve());
});
}
}
// Image caching for better performance
class ImageCache {
private cache = new Map<string, boolean>();
async preloadImage(src: string): Promise<boolean> {
if (this.cache.has(src)) {
return true;
}
return new Promise((resolve) => {
const img = new Image();
img.onload = () => {
this.cache.set(src, true);
resolve(true);
};
img.onerror = () => {
resolve(false);
};
img.src = src;
});
}
isImageLoaded(src: string): boolean {
return this.cache.has(src);
}
async preloadImages(sources: string[]): Promise<boolean[]> {
return Promise.all(sources.map(src => this.preloadImage(src)));
}
}Canvas operations can fail due to invalid parameters, missing resources, or browser limitations.
// Safe canvas operations
async function safeCanvasOperation<T>(
operation: () => Promise<T>,
fallback?: () => T,
errorMessage = 'Canvas operation failed'
): Promise<T | null> {
try {
return await operation();
} catch (error: any) {
console.error(errorMessage, error);
await showToast({
title: errorMessage,
icon: 'error'
});
return fallback ? fallback() : null;
}
}
// Usage
const imagePath = await safeCanvasOperation(
() => canvasToTempFilePath({
canvasId: 'myCanvas',
fileType: 'png'
}).then(result => result.tempFilePath),
() => '', // Fallback to empty string
'Failed to export canvas'
);interface CallbackOptions {
success?: (res: any) => void;
fail?: (err: any) => void;
complete?: (res: any) => void;
}
type ImageFileType = 'jpg' | 'png';
type FillStyle = string | CanvasGradient | CanvasPattern;
type StrokeStyle = string | CanvasGradient | CanvasPattern;Install with Tessl CLI
npx tessl i tessl/npm-tarojs--taro-h5