Skip to content

Commit

Permalink
Merge pull request #5 from js-tool-pack/image
Browse files Browse the repository at this point in the history
Image
  • Loading branch information
mengxinssfd authored Mar 7, 2024
2 parents 8f42e9c + 5067a84 commit b9eb3a9
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 29 deletions.
3 changes: 3 additions & 0 deletions packages/core/src/Graphics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ export abstract class Graphics {
remove() {
this.parent?.removeChild(this);
}
update() {
this.renderer?.render();
}
abstract drawPath(ctx: CanvasRenderingContext2D, style: Style): void;
abstract render(ctx: CanvasRenderingContext2D): void;
}
87 changes: 87 additions & 0 deletions packages/core/src/image/demo/basic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* title: 基础用法
*/

import { Renderer, Image } from '@tool-pack/canvas';
import React, { useEffect, useRef } from 'react';

const App: React.FC = () => {
const elRef = useRef<HTMLCanvasElement>(null);

useEffect(() => {
const el = elRef.current;
if (!el) return;

const renderer = new Renderer(el);
const img = new Image(
'https://s.cn.bing.net/th?id=OHR.BangkokCircle_ZH-CN4702412806_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
{
borderRadius: 20,
height: 100,
width: 100,
top: 100,
left: 0,
},
);
// 划过时切换图片
img.addEventListener('mouseenter', function () {
this.src =
'https://s.cn.bing.net/th?id=OHR.ArenalCostaRica_ZH-CN4466297855_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp';
});
img.addEventListener('mouseleave', function () {
this.src =
'https://s.cn.bing.net/th?id=OHR.BangkokCircle_ZH-CN4702412806_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp';
});

const images = [
new Image(
'https://s.cn.bing.net/th?id=OHR.TarragonaSpain_ZH-CN5488361711_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
{
height: 100,
width: 100,
},
),
new Image(
'https://s.cn.bing.net/th?id=OHR.WahclellaFalls_ZH-CN4932852217_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
{
borderColor: 'deeppink',
borderRadius: 20,
borderWidth: 5,
height: 100,
width: 100,
left: 100,
top: 0,
},
),
img,
new Image(
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fphotoblog%2F1610%2F20%2Fc16%2F28666491_1476977210753.jpg&refer=http%3A%2F%2Fimg.pconline.com.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639854808&t=8c31d1b0991a4c8a5068e9f303c1fe90',
{
borderColor: '#00e09e',
borderWidth: 5,
height: 100,
width: 100,
left: 100,
top: 100,
},
),
] as const;

images.forEach((img) => renderer.add(img));
renderer.render();

return () => renderer.destroy();
}, []);

return (
<canvas
style={{ border: '1px solid pink' }}
draggable="false"
height={200}
width={200}
ref={elRef}
/>
);
};

export default App;
20 changes: 20 additions & 0 deletions packages/core/src/image/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
category: Core
title: Image 图片
atomId: Image
nav:
title: Core
demo:
cols: 2
group:
title: 基础
---

Image 图片

## 代码演示

<!-- prettier-ignore -->
<code src="./demo/basic.tsx"></code>

## API
59 changes: 59 additions & 0 deletions packages/core/src/image/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Rectangle } from '~/rectangle';
import { Style } from '~/Style';

export class Image extends Rectangle {
private img!: HTMLImageElement;
private _src!: string;
crossOrigin: string | null = null;

constructor(src?: string, style?: Partial<Style>) {
super(style);
if (src) this._src = src;
this.createImgElement();
}

private drawImg(ctx: CanvasRenderingContext2D): void {
const pattern = ctx.createPattern(this.img, 'no-repeat');
const { left = 0, top = 0, height, width } = this.computedStyle;
const { naturalHeight, naturalWidth } = this.img;

this.drawPathWithoutBorder(ctx);
if (pattern) {
// 注意:translate 和 scale 的先后顺序会影响实际位置,必须先移动再缩放
const matrix = new DOMMatrix()
.translate(left, top)
.scale(width / naturalWidth, height / naturalHeight);

pattern.setTransform(matrix);
ctx.fillStyle = pattern;
ctx.fill();
}
}

private createImgElement(): void {
const img = (this.img = document.createElement('img'));
img.crossOrigin = this.crossOrigin;
img.onload = () => {
this.computedStyle.width ||= img.width;
this.computedStyle.height ||= img.height;
this.update();
};
img.onerror = img.oncancel = (): void => {
console.error(`'${this._src}' load fail`);
};
img.src = this._src;
}
override render(ctx: CanvasRenderingContext2D): void {
// super.render(ctx);
this.renderBackground(ctx);
this.drawImg(ctx);
this.renderBorder(ctx);
}
set src(src: string) {
this._src = src;
this.img.src = src;
}
get src(): string {
return this._src;
}
}
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './Renderer';
export * from './Style';
export * from './rectangle';
export * from './pencil';
export * from './image';
2 changes: 1 addition & 1 deletion packages/core/src/rectangle/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ demo:
cols: 2
group:
order: 0
title: 形状
title: 基础
---

Rectangle 矩形
Expand Down
58 changes: 30 additions & 28 deletions packages/core/src/rectangle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,31 @@ import { Graphics } from '~/Graphics';
import { Style } from '~/Style';

export class Rectangle extends Graphics {
private drawPathWithoutBorder(ctx: CanvasRenderingContext2D): void {
override drawPath(ctx: CanvasRenderingContext2D, style: Style): void {
let {
borderRadius: r = 0,
left: x = 0,
top: y = 0,
height: h,
width: w,
} = style;
ctx.beginPath();
// ctx.rect(x, y, w, h);

if (w < 2 * r) r = w / 2;
if (h < 2 * r) r = h / 2;
ctx.beginPath();

// ctx.moveTo(x + r, y);
// ctx.arcTo(x + w, y, x + w, y + h, r);
// ctx.arcTo(x + w, y + h, x, y + h, r);
// ctx.arcTo(x, y + h, x, y, r);
// ctx.arcTo(x, y, x + w, y, r);

ctx.roundRect(x, y, w, h, r);
ctx.closePath();
}
protected drawPathWithoutBorder(ctx: CanvasRenderingContext2D): void {
const style = this.computedStyle;
const bw = style.borderWidth || 0;
this.drawPath(ctx, {
Expand All @@ -13,7 +37,7 @@ export class Rectangle extends Graphics {
width: style.width - bw,
});
}
private renderBorder(ctx: CanvasRenderingContext2D): void {
protected renderBorder(ctx: CanvasRenderingContext2D): void {
const style = this.computedStyle;
if (!style.borderWidth) return;

Expand All @@ -24,37 +48,15 @@ export class Rectangle extends Graphics {

ctx.stroke();
}
private renderBackground(ctx: CanvasRenderingContext2D): void {
protected renderBackground(ctx: CanvasRenderingContext2D): void {
const { computedStyle: style } = this;
style.backgroundColor && (ctx.fillStyle = style.backgroundColor);
if (!style.backgroundColor) return;

ctx.fillStyle = style.backgroundColor;
// this.drawPath(ctx, style);
this.drawPathWithoutBorder(ctx);
ctx.fill();
}
override drawPath(ctx: CanvasRenderingContext2D, style: Style): void {
let {
borderRadius: r = 0,
left: x = 0,
top: y = 0,
height: h,
width: w,
} = style;
ctx.beginPath();
// ctx.rect(x, y, w, h);

if (w < 2 * r) r = w / 2;
if (h < 2 * r) r = h / 2;
ctx.beginPath();

// ctx.moveTo(x + r, y);
// ctx.arcTo(x + w, y, x + w, y + h, r);
// ctx.arcTo(x + w, y + h, x, y + h, r);
// ctx.arcTo(x, y + h, x, y, r);
// ctx.arcTo(x, y, x + w, y, r);

ctx.roundRect(x, y, w, h, r);
ctx.closePath();
}
override render(ctx: CanvasRenderingContext2D): void {
this.renderBackground(ctx);
this.renderBorder(ctx);
Expand Down

0 comments on commit b9eb3a9

Please sign in to comment.