-
Notifications
You must be signed in to change notification settings - Fork 605
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(pattern): 使用setTransform方法,rotation作用于整个pattern画布 (#2789)
* refactor(pattern): 使用setTransform方法,rotation作用于整个pattern画布 * refactor: 处理transformMatrix成纯函数 * refactor: 处理transformMatrix成纯函数 * test(dot and util): 添加dotPattern和util的单测,并添加getPixelColor获取像素点方法 * test(line-pattern): 添加linePattern的单测 * test(square-pattern): 添加squarePattern的单测 * refactor: 修改变换矩阵的写法 Co-authored-by: 酥云 <lisuwen.lsw@antgroup.com>
- Loading branch information
Showing
11 changed files
with
354 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { initCanvas } from '../../../../src/utils/pattern/util'; | ||
import { drawDot, defaultDotPatternCfg, createDotPattern } from '../../../../src/utils/pattern/dot'; | ||
import { DotPatternCfg } from '../../../../src/types/pattern'; | ||
import { getPixelColor } from '../../../utils/getPixelColor'; | ||
import { deepAssign } from '../../../../src/utils'; | ||
|
||
describe('utils: dot pattern', () => { | ||
const width = 30, | ||
height = 30; | ||
const canvas = initCanvas(width, height); | ||
const ctx = canvas.getContext('2d'); | ||
document.body.appendChild(canvas); | ||
|
||
it('createDotPattern with defaultCfg', () => { | ||
const pattern = createDotPattern(defaultDotPatternCfg as DotPatternCfg); | ||
expect(pattern.toString()).toEqual('[object CanvasPattern]'); | ||
}); | ||
|
||
it('dotUnitPattern with fill', () => { | ||
const cfg = deepAssign(defaultDotPatternCfg, { | ||
// radius: 4, // 默认 | ||
fill: '#898989', | ||
}); | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawDot(ctx, cfg as DotPatternCfg, width / 2, height / 2); | ||
// 传入的是呈现的位置 | ||
expect(getPixelColor(canvas, width / 2, height / 2).hex).toEqual('#898989'); | ||
expect(getPixelColor(canvas, width / 2 + cfg.radius, height / 2 + cfg.radius).hex).toEqual('#000000'); // 超出圆范围, 像素点在右下方 | ||
}); | ||
|
||
it('dotUnitPattern with fillOpacity', () => { | ||
const cfg = deepAssign(defaultDotPatternCfg, { | ||
// radius: 4, // 默认 | ||
fill: '#898989', | ||
fillOpacity: 0.5, | ||
}); | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawDot(ctx, cfg as DotPatternCfg, width / 2, height / 2); | ||
// 传入的是呈现的位置 | ||
expect(getPixelColor(canvas, width / 2, height / 2).alpha.toPrecision(1)).toEqual(`${0.5}`); | ||
expect(getPixelColor(canvas, width / 2 + cfg.radius, height / 2 + cfg.radius).alpha.toPrecision(1)).toEqual(`${0}`); // 透明度为0 | ||
}); | ||
|
||
it('dotUnitPattern with radius', () => { | ||
const radius = 15; | ||
const cfg = deepAssign(defaultDotPatternCfg, { | ||
fill: '#ff0000', | ||
fillOpacity: 1, | ||
radius, | ||
}); | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawDot(ctx, cfg as DotPatternCfg, width / 2, height / 2); | ||
// 传入的是呈现的位置 | ||
expect(getPixelColor(canvas, width / 2, height / 2).hex).toEqual('#ff0000'); | ||
expect(getPixelColor(canvas, width / 2 + radius - 1, height / 2).hex).toEqual('#ff0000'); // 圆的边界 | ||
expect(getPixelColor(canvas, width / 2 + radius, height / 2).hex).toEqual('#000000'); | ||
}); | ||
|
||
it('dotUnitPattern with stroke and lineWidth', () => { | ||
const cfg = deepAssign(defaultDotPatternCfg, { | ||
radius: 10, | ||
fill: '#ff0000', | ||
stroke: '#00ff00', | ||
lineWidth: 2, | ||
}); | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawDot(ctx, cfg as DotPatternCfg, width / 2, height / 2); | ||
// 传入的是呈现的位置 | ||
expect(getPixelColor(canvas, width / 2, height / 2).hex).toEqual('#ff0000'); | ||
expect(getPixelColor(canvas, width / 2 + cfg.radius, height / 2).hex).toEqual('#00ff00'); | ||
expect(getPixelColor(canvas, width / 2 + cfg.radius, height / 2 + cfg.radius).hex).toEqual('#000000'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { initCanvas } from '../../../../src/utils/pattern/util'; | ||
import { defaultLinePatternCfg, createLinePattern, drawLine } from '../../../../src/utils/pattern/line'; | ||
import { LinePatternCfg } from '../../../../src/types/pattern'; | ||
import { getPixelColor } from '../../../utils/getPixelColor'; | ||
import { deepAssign } from '../../../../src/utils'; | ||
|
||
describe('utils: line pattern', () => { | ||
const width = 30, | ||
height = 30; | ||
const canvas = initCanvas(width, height); | ||
const ctx = canvas.getContext('2d'); | ||
document.body.appendChild(canvas); | ||
|
||
it('createLinePattern with defaultCfg', () => { | ||
const pattern = createLinePattern(defaultLinePatternCfg as LinePatternCfg); | ||
expect(pattern.toString()).toEqual('[object CanvasPattern]'); | ||
}); | ||
|
||
it('lineUnitPattern with stroke and strokeWidth', () => { | ||
const cfg = deepAssign(defaultLinePatternCfg, { | ||
stroke: '#ff0000', | ||
lineWidth: 2, | ||
}); | ||
const d = ` | ||
M 0 0 L ${width} 0 | ||
M 0 ${height} L ${width} ${height} | ||
`; | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawLine(ctx, cfg as LinePatternCfg, d); | ||
// 传入的是呈现的位置 | ||
expect(getPixelColor(canvas, 0, 0).hex).toEqual('#ff0000'); | ||
expect(getPixelColor(canvas, 0, height - 1).hex).toEqual('#ff0000'); | ||
}); | ||
|
||
it('lineUnitPattern with strokeOpacity', () => { | ||
const cfg = deepAssign(defaultLinePatternCfg, { | ||
stroke: '#ff0000', | ||
lineWidth: 2, | ||
strokeOpacity: 0.5, | ||
}); | ||
const d = ` | ||
M 0 0 L ${width} 0 | ||
M 0 ${height} L ${width} ${height} | ||
`; | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawLine(ctx, cfg as LinePatternCfg, d); | ||
// 传入的是呈现的位置 | ||
expect(getPixelColor(canvas, 0, 0).alpha.toPrecision(1)).toEqual(`${0.5}`); | ||
expect(getPixelColor(canvas, 0, height - 1).alpha.toPrecision(1)).toEqual(`${0.5}`); | ||
expect(getPixelColor(canvas, width / 2, height / 2).alpha.toPrecision(1)).toEqual(`${0}`); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { initCanvas } from '../../../../src/utils/pattern/util'; | ||
import { drawSquare, defaultSquarePatternCfg, createSquarePattern } from '../../../../src/utils/pattern/square'; | ||
import { SquarePatternCfg } from '../../../../src/types/pattern'; | ||
import { getPixelColor } from '../../../utils/getPixelColor'; | ||
import { deepAssign } from '../../../../src/utils'; | ||
|
||
describe('utils: square pattern', () => { | ||
const width = 30, | ||
height = 30; | ||
const canvas = initCanvas(width, height); | ||
const ctx = canvas.getContext('2d'); | ||
document.body.appendChild(canvas); | ||
|
||
it('createSquarePattern with defaultCfg', () => { | ||
const pattern = createSquarePattern(defaultSquarePatternCfg as SquarePatternCfg); | ||
expect(pattern.toString()).toEqual('[object CanvasPattern]'); | ||
}); | ||
|
||
it('squareUnitPattern with fill', () => { | ||
const cfg = deepAssign(defaultSquarePatternCfg, { | ||
fill: '#898989', | ||
}); | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawSquare(ctx, cfg as SquarePatternCfg, width / 2, height / 2); | ||
// 传入的是呈现的位置 | ||
expect(getPixelColor(canvas, width / 2, height / 2).hex).toEqual('#898989'); | ||
expect(getPixelColor(canvas, width / 2 + cfg.size + 5, height / 2).hex).toEqual('#000000'); // 超出范围 | ||
}); | ||
|
||
it('squareUnitPattern with fillOpacity', () => { | ||
const cfg = deepAssign(defaultSquarePatternCfg, { | ||
// radius: 4, // 默认 | ||
fill: '#898989', | ||
fillOpacity: 0.5, | ||
}); | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawSquare(ctx, cfg as SquarePatternCfg, width / 2, height / 2); | ||
// 传入的是呈现的位置 | ||
expect(getPixelColor(canvas, width / 2, height / 2).alpha.toPrecision(1)).toEqual(`${0.5}`); | ||
expect(getPixelColor(canvas, width / 2 + cfg.size + 5, height / 2).alpha.toPrecision(1)).toEqual(`${0}`); // 透明度为0 | ||
}); | ||
|
||
it('squareUnitPattern with size', () => { | ||
const size = 15; | ||
const cfg = deepAssign(defaultSquarePatternCfg, { | ||
fill: '#898989', | ||
fillOpacity: 1, | ||
size, | ||
}); | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawSquare(ctx, cfg as SquarePatternCfg, width / 2, height / 2); | ||
// 传入的是呈现的位置 | ||
expect(getPixelColor(canvas, width / 2, height / 2).hex).toEqual('#898989'); | ||
expect(getPixelColor(canvas, width / 2 + size / 2 - 1, height / 2).hex).toEqual('#898989'); // 边界 | ||
expect(getPixelColor(canvas, width / 2 + size / 2 + 5, height / 2).hex).toEqual('#000000'); // 超出边界 | ||
}); | ||
|
||
it('squareUnitPattern with stroke and lineWidth', () => { | ||
const cfg = deepAssign(defaultSquarePatternCfg, { | ||
size: 15, | ||
fill: '#ff0000', | ||
stroke: '#00ff00', | ||
lineWidth: 2, | ||
}); | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
drawSquare(ctx, cfg as SquarePatternCfg, width / 2, height / 2); | ||
// 传入的是呈现的位置 | ||
expect(getPixelColor(canvas, width / 2, height / 2).hex).toEqual('#ff0000'); | ||
expect(getPixelColor(canvas, width / 2 + cfg.size / 2, height / 2).hex).toEqual('#00ff00'); | ||
expect(getPixelColor(canvas, width / 2 + cfg.size / 2 + 5, height / 2 + cfg.size / 2).hex).toEqual('#000000'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { | ||
initCanvas, | ||
getUnitPatternSize, | ||
getSymbolsPosition, | ||
drawBackground, | ||
transformMatrix, | ||
} from '../../../../src/utils/pattern/util'; | ||
import { DotPatternCfg } from '../../../../src/types/pattern'; | ||
import { getPixelColor } from '../../../utils/getPixelColor'; | ||
|
||
describe('utils', () => { | ||
const width = 30, | ||
height = 30; | ||
let canvas = null; | ||
|
||
it('initCanvas', () => { | ||
canvas = initCanvas(width, height); | ||
document.body.appendChild(canvas); | ||
expect(canvas.width).toBe(60); | ||
expect(canvas.height).toBe(60); | ||
}); | ||
|
||
it('getPixelColor', () => { | ||
const ctx = canvas.getContext('2d'); | ||
ctx.fillStyle = '#989898'; | ||
ctx.fillRect(0, 0, canvas.width, canvas.height); | ||
expect(getPixelColor(canvas, width / 2, height / 2).hex).toEqual('#989898'); | ||
expect(getPixelColor(canvas, width + 1, height + 1).hex).toEqual('#000000'); // 超出范围,黑色 | ||
}); | ||
|
||
it('drawBackground', () => { | ||
const defaultDotPatternCfg = { | ||
backgroundColor: '#eee', // 为了测试背景色填充 | ||
}; | ||
const ctx = canvas.getContext('2d'); | ||
drawBackground(ctx, defaultDotPatternCfg as DotPatternCfg, width, height); | ||
const color = getPixelColor(canvas, width / 2, height / 2).hex; | ||
expect(color).toEqual('#eeeeee'); | ||
}); | ||
|
||
it('getUnitPatternSize', () => { | ||
expect(getUnitPatternSize(4, 6, false)).toBe(10); | ||
expect(getUnitPatternSize(4, 6, true)).toBe(20); | ||
}); | ||
|
||
it('getSymbolsPosition', () => { | ||
expect(getSymbolsPosition(12, false)).toEqual([[6, 6]]); | ||
expect(getSymbolsPosition(12, true)).toEqual([ | ||
[3, 3], | ||
[9, 9], | ||
]); | ||
}); | ||
|
||
it('transformMatrix', () => { | ||
expect(transformMatrix(2, 45).toString()).toEqual( | ||
'matrix(0.3535533905932738, 0.35355339059327373, -0.35355339059327373, 0.3535533905932738, 0, 0)' | ||
); | ||
expect(transformMatrix(1, 45).toString()).toEqual( | ||
'matrix(0.7071067811865476, 0.7071067811865475, -0.7071067811865475, 0.7071067811865476, 0, 0)' | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/** | ||
* @param canvas | ||
* @param x和y 呈现的坐标位置 | ||
*/ | ||
export function getPixelColor(canvas: HTMLCanvasElement, x: number, y: number) { | ||
const dpr = window.devicePixelRatio || 2; | ||
const ctx = canvas.getContext('2d'); | ||
// ctx 获取的是实际渲染的图形的位置,所以需要:呈现的坐标位置 * dpr | ||
const pixel = ctx.getImageData(x * dpr, y * dpr, 1, 1); | ||
const data = pixel.data; // [r, g, b, a] 暂不处理透明度情况 | ||
|
||
// 如果 x, y 超出图像边界,则是透明黑色(全为零,即 rgba(0,0,0,0)) | ||
// 详见:https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas | ||
const rHex = fixTwoDigit(data[0].toString(16)); | ||
const gHex = fixTwoDigit(data[1].toString(16)); | ||
const bHex = fixTwoDigit(data[2].toString(16)); | ||
const hex = `#${rHex}${gHex}${bHex}`; | ||
|
||
const alpha = data[3] / 255; | ||
|
||
return { hex, alpha }; | ||
} | ||
|
||
function fixTwoDigit(str) { | ||
return str.length < 2 ? `0${str}` : `${str}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.