Skip to content

Commit

Permalink
feat: support dynamicTexture
Browse files Browse the repository at this point in the history
  • Loading branch information
neuqzxy committed Feb 14, 2025
1 parent ba8f989 commit 0c66f83
Show file tree
Hide file tree
Showing 12 changed files with 875 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@visactor/vrender-core",
"comment": "feat: support dynamicTexture",
"type": "none"
}
],
"packageName": "@visactor/vrender-core"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@visactor/vrender-kits",
"comment": "feat: support dynamicTexture",
"type": "none"
}
],
"packageName": "@visactor/vrender-kits"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@visactor/vrender",
"comment": "",
"type": "none"
}
],
"packageName": "@visactor/vrender"
}
2 changes: 1 addition & 1 deletion packages/vrender-core/src/graphic/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export const DefaultStyle: IGraphicStyle = {
opacity: 1,
background: null,
autoAnimateTexture: false,
textureRatio: 0,
textureRatio: 1,
textureOptions: null,
backgroundOpacity: 1,
backgroundCornerRadius: 0,
Expand Down
14 changes: 14 additions & 0 deletions packages/vrender-core/src/graphic/symbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ export class Symbol extends Graphic<ISymbolGraphicAttribute> implements ISymbol
return this._parsedPath as ISymbolClass;
}

getParsedPath2D(x = 0, y = 0, size = 1): Path2D | null {
let path: Path2D | null = null;
try {
path = new Path2D();
} catch (err) {
return null;
}
const parsedPath = this.getParsedPath();
if (!parsedPath) {
return null;
}
parsedPath.draw(path, size, x, y);
}

isValid(): boolean {
return super.isValid() && this._isValid();
}
Expand Down
1 change: 1 addition & 0 deletions packages/vrender-core/src/interface/graphic/symbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type ISymbolGraphicAttribute = Partial<IGraphicAttribute> & Partial<ISymb

export interface ISymbol extends IGraphic<ISymbolGraphicAttribute> {
getParsedPath: () => ISymbolClass;
getParsedPath2D: (x?: number, y?: number, size?: number) => Path2D | null;
}

export type SymbolType =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { canvasAllocate } from '../../../../allocator/canvas-allocate';
import { BaseRenderContributionTime } from '../../../../common/enums';
import { createSymbol } from '../../../../graphic';
import type {
IBaseRenderContribution,
IContext2d,
IDrawContext,
IGraphic,
IGraphicAttribute,
IStage,
ISymbol,
IThemeAttribute
} from '../../../../interface';
import { pi2 } from '@visactor/vutils';
Expand Down Expand Up @@ -68,6 +70,7 @@ export class DefaultBaseTextureRenderContribution implements IBaseRenderContribu
useStyle: boolean = true;
textureMap?: Map<string, CanvasPattern>;
order: number = 10;
_tempSymbolGraphic: ISymbol | null = null;

createCommonPattern(
size: number,
Expand Down Expand Up @@ -274,7 +277,46 @@ export class DefaultBaseTextureRenderContribution implements IBaseRenderContribu
}
}

if (pattern) {
if (textureOptions && textureOptions.dynamicTexture) {
// 动态纹理
context.save();
context.setCommonStyle(graphic, graphic.attribute, x, y, graphicAttribute);
context.clip();
const { gridConfig = {} } = textureOptions;
const b = graphic.AABBBounds;
const width = b.width();
const height = b.height();
const padding = texturePadding;
const cellSize = textureSize;
const gridColumns = gridConfig.columns ? gridConfig.columns : Math.ceil(width / cellSize);
const gridRows = gridConfig.rows ? gridConfig.rows : Math.ceil(height / cellSize);
const gutterColumn = gridConfig.gutterColumn ? gridConfig.gutterColumn : padding * 2;
const gutterRow = gridConfig.gutterRow ? gridConfig.gutterRow : padding * 2;
if (!this._tempSymbolGraphic) {
this._tempSymbolGraphic = createSymbol({});
}
const sizeW = gridConfig.columns ? width / gridConfig.columns : cellSize;
const sizeH = gridConfig.rows ? height / gridConfig.rows : cellSize;
this._tempSymbolGraphic.setAttributes({
size: [sizeW - gutterColumn, sizeH - gutterRow],
symbolType: texture
});
const parsedPath = this._tempSymbolGraphic.getParsedPath();
for (let i = 0; i < gridRows; i++) {
for (let j = 0; j < gridColumns; j++) {
const _x = x + cellSize / 2 + j * cellSize;
const _y = y + cellSize / 2 + i * cellSize;
context.beginPath();
if (parsedPath.draw(context, Math.min(sizeW - gutterColumn, sizeH - gutterRow), _x, _y, 0) === false) {
context.closePath();
}
context.fillStyle = textureColor;
textureOptions.dynamicTexture(context, i, j, gridRows, gridColumns, textureRatio, graphic);
}
}

context.restore();
} else if (pattern) {
context.highPerformanceSave();
context.setCommonStyle(graphic, graphic.attribute, x, y, graphicAttribute);
context.fillStyle = pattern;
Expand Down
1 change: 1 addition & 0 deletions packages/vrender-kits/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,6 @@ export * from './register/register-shadowRoot';
export * from './register/register-symbol';
export * from './register/register-text';
export * from './register/register-wraptext';
export * from './tools/dynamicTexture/effect';
// export const canvasModuleLoader = _canvasModuleLoader;
// export { nodeLoader } from './node-bind'; // nodeLoader只在node入口暴露
229 changes: 229 additions & 0 deletions packages/vrender-kits/src/tools/dynamicTexture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
// import type { IContext2d, IGraphic } from '@visactor/vrender-core';

// export function randomOpacity(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// if (!graphic.dynamicTextureCache) {
// graphic.dynamicTextureCache = new Array(rowCount * columnCount).fill(0).map(item => Math.random() * 2 * Math.PI);
// }
// const targetRandomValue = graphic.dynamicTextureCache[row * columnCount + column];
// const _r = (Math.sin(ratio * 2 * Math.PI + targetRandomValue) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 从左到右的列式渐变
// export function columnLeftToRight(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// // 根据列号计算延迟
// const delay = column / columnCount;
// // 使用连续的sin函数,不需要max(0,ratio-delay)的截断
// const _r = (Math.sin(ratio * 2 * Math.PI - delay * 2 * Math.PI) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 从右到左的列式渐变
// export function columnRightToLeft(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// const delay = (columnCount - 1 - column) / columnCount;
// const _r = (Math.sin(ratio * 2 * Math.PI - delay * 2 * Math.PI) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 从上到下的行式渐变
// export function rowTopToBottom(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// const delay = row / rowCount;
// const _r = (Math.sin(ratio * 2 * Math.PI - delay * 2 * Math.PI) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 从下到上的行式渐变
// export function rowBottomToTop(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// const delay = (rowCount - 1 - row) / rowCount;
// const _r = (Math.sin(ratio * 2 * Math.PI - delay * 2 * Math.PI) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 从中心向两边的对角线渐变
// export function diagonalCenterToEdge(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// const centerRow = rowCount / 2;
// const centerCol = columnCount / 2;
// const distance = Math.sqrt(
// Math.pow((row - centerRow) / rowCount, 2) + Math.pow((column - centerCol) / columnCount, 2)
// );
// const _r = (Math.sin(ratio * 2 * Math.PI - distance * 2 * Math.PI) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 从左上角到右下角的对角线渐变
// export function diagonalTopLeftToBottomRight(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// const delay = (row / rowCount + column / columnCount) / 2;
// const _r = (Math.sin(ratio * 2 * Math.PI - delay * 2 * Math.PI) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 旋转扫描效果
// export function rotationScan(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// // 计算当前点相对于中心点的角度
// const centerRow = rowCount / 2;
// const centerCol = columnCount / 2;
// const angle = Math.atan2(row - centerRow, column - centerCol);
// // 将角度归一化到 [0, 2π]
// const normalizedAngle = angle < 0 ? angle + 2 * Math.PI : angle;
// // 计算扫描延迟
// const delay = normalizedAngle / (2 * Math.PI);
// const _r = (Math.sin(ratio * 2 * Math.PI - delay * 2 * Math.PI) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 波纹扩散效果
// export function rippleEffect(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// const centerRow = rowCount / 2;
// const centerCol = columnCount / 2;
// // 计算到中心的距离
// const distance = Math.sqrt(Math.pow(row - centerRow, 2) + Math.pow(column - centerCol, 2));
// // 归一化距离
// const normalizedDistance = distance / Math.sqrt(Math.pow(rowCount / 2, 2) + Math.pow(columnCount / 2, 2));
// // 创建多个波纹
// const waves = 3;
// const _r = (Math.sin(ratio * 2 * Math.PI * waves - normalizedDistance * 2 * Math.PI) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 蛇形波动效果
// export function snakeWave(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// // 使用行和列的位置创建蛇形路径
// const delay = ((row + column) % (rowCount + columnCount)) / (rowCount + columnCount);
// const _r = (Math.sin(ratio * 2 * Math.PI - delay * 4 * Math.PI) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 交错波纹效果
// export function alternatingWave(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// // 行和列的交错波纹
// const rowPhase = row / rowCount;
// const colPhase = column / columnCount;
// const _r =
// (Math.sin(ratio * 2 * Math.PI - rowPhase * 2 * Math.PI) * Math.sin(ratio * 2 * Math.PI - colPhase * 2 * Math.PI) +
// 1) /
// 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }

// // 螺旋效果
// export function spiralEffect(
// ctx: IContext2d,
// row: number,
// column: number,
// rowCount: number,
// columnCount: number,
// ratio: number,
// graphic: IGraphic
// ) {
// const centerRow = rowCount / 2;
// const centerCol = columnCount / 2;
// // 计算到中心的距离和角度
// const distance = Math.sqrt(Math.pow(row - centerRow, 2) + Math.pow(column - centerCol, 2));
// const angle = Math.atan2(row - centerRow, column - centerCol);
// // 归一化距离
// const normalizedDistance = distance / Math.sqrt(Math.pow(rowCount / 2, 2) + Math.pow(columnCount / 2, 2));
// // 组合距离和角度创建螺旋效果
// const delay = (normalizedDistance + angle / (2 * Math.PI)) / 2;
// const _r = (Math.sin(ratio * 2 * Math.PI - delay * 4 * Math.PI) + 1) / 2;
// ctx.globalAlpha = _r;
// ctx.fill();
// }
Loading

0 comments on commit 0c66f83

Please sign in to comment.