Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading