bak
This commit is contained in:
1 parent
6b6157d786
commit
3ef5fb5a2d
19 files changed
+1244
-94
No files matched your search
@@ -149,18 +149,38 @@ const ENGINE_SOURCE = `(function(){
|
||||
ctx.translate(p.x,p.y);
|
||||
ctx.rotate(p.rotation*Math.PI/180);
|
||||
ctx.scale(p.scaleX,p.scaleY);
|
||||
var sOp=p.shadowOpacity||0;
|
||||
var sBl=p.shadowBlur||0;
|
||||
var sDi=p.shadowDistance||0;
|
||||
if(sOp>0 && (sBl>0 || sDi>0)){
|
||||
var sAn=(p.shadowAngle==null?90:p.shadowAngle)*Math.PI/180;
|
||||
var sHex=(p.shadowColor||'#000000').replace('#','');
|
||||
if(sHex.length===3){sHex=sHex[0]+sHex[0]+sHex[1]+sHex[1]+sHex[2]+sHex[2];}
|
||||
var sNum=parseInt(sHex.slice(0,6),16);
|
||||
if(isNaN(sNum))sNum=0;
|
||||
ctx.shadowColor='rgba('+((sNum>>16)&255)+','+((sNum>>8)&255)+','+(sNum&255)+','+sOp+')';
|
||||
ctx.shadowBlur=sBl;
|
||||
ctx.shadowOffsetX=Math.cos(sAn)*sDi;
|
||||
ctx.shadowOffsetY=Math.sin(sAn)*sDi;
|
||||
}
|
||||
if(asset.kind==='rect'){
|
||||
var rOffX=layer.offsetX!=null?layer.offsetX:asset.width/2;
|
||||
var rOffY=layer.offsetY!=null?layer.offsetY:asset.height/2;
|
||||
var rBlur=(p.blur!=null?p.blur:(asset.blur||0));
|
||||
ctx.fillStyle=p.fill||asset.fill;
|
||||
if(rBlur>0) ctx.filter='blur('+rBlur+'px)';
|
||||
ctx.fillRect(-rOffX,-rOffY,asset.width,asset.height);
|
||||
ctx.filter='none';
|
||||
}else if(asset.kind==='circle'){
|
||||
var cOffX=layer.offsetX!=null?layer.offsetX:0;
|
||||
var cOffY=layer.offsetY!=null?layer.offsetY:0;
|
||||
var cBlur=(p.blur!=null?p.blur:(asset.blur||0));
|
||||
ctx.fillStyle=p.fill||asset.fill;
|
||||
if(cBlur>0) ctx.filter='blur('+cBlur+'px)';
|
||||
ctx.beginPath();
|
||||
ctx.arc(-cOffX,-cOffY,asset.radius,0,Math.PI*2);
|
||||
ctx.fill();
|
||||
ctx.filter='none';
|
||||
}else if(asset.kind==='text'){
|
||||
var tOffX=layer.offsetX!=null?layer.offsetX:0;
|
||||
var tOffY=layer.offsetY!=null?layer.offsetY:0;
|
||||
@@ -176,6 +196,10 @@ const ENGINE_SOURCE = `(function(){
|
||||
ctx.drawImage(img,-iOffX,-iOffY,asset.width,asset.height);
|
||||
}
|
||||
}
|
||||
ctx.shadowColor='transparent';
|
||||
ctx.shadowBlur=0;
|
||||
ctx.shadowOffsetX=0;
|
||||
ctx.shadowOffsetY=0;
|
||||
ctx.restore();
|
||||
}
|
||||
function draw(time){
|
||||
|
||||
@@ -49,6 +49,19 @@ function lerpProps(a: AnimatableProps, b: AnimatableProps, t: number): Animatabl
|
||||
if (a.fill && b.fill) out.fill = lerpColor(a.fill, b.fill, t)
|
||||
else if (b.fill) out.fill = b.fill
|
||||
else if (a.fill) out.fill = a.fill
|
||||
if (a.blur !== undefined && b.blur !== undefined) out.blur = lerp(a.blur, b.blur, t)
|
||||
else if (b.blur !== undefined) out.blur = b.blur
|
||||
else if (a.blur !== undefined) out.blur = a.blur
|
||||
for (const key of ['shadowBlur', 'shadowOpacity', 'shadowAngle', 'shadowDistance'] as const) {
|
||||
const av = a[key]
|
||||
const bv = b[key]
|
||||
if (av !== undefined && bv !== undefined) out[key] = lerp(av, bv, t)
|
||||
else if (bv !== undefined) out[key] = bv
|
||||
else if (av !== undefined) out[key] = av
|
||||
}
|
||||
if (a.shadowColor && b.shadowColor) out.shadowColor = lerpColor(a.shadowColor, b.shadowColor, t)
|
||||
else if (b.shadowColor) out.shadowColor = b.shadowColor
|
||||
else if (a.shadowColor) out.shadowColor = a.shadowColor
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
+71
-3
@@ -1,4 +1,4 @@
|
||||
import type { Asset, Layer, Scene } from '@/types/scene'
|
||||
import type { AnimatableProps, Asset, Layer, Scene } from '@/types/scene'
|
||||
import { sampleLayer } from './interpolate'
|
||||
|
||||
export async function loadSceneImages(scene: Scene): Promise<Record<string, HTMLImageElement>> {
|
||||
@@ -24,6 +24,62 @@ export async function loadSceneImages(scene: Scene): Promise<Record<string, HTML
|
||||
return result
|
||||
}
|
||||
|
||||
interface ShadowState {
|
||||
sx: number
|
||||
sy: number
|
||||
blur: number
|
||||
color: string
|
||||
}
|
||||
|
||||
function hexToRgba(hex: string, alpha: number): string {
|
||||
const h = hex.trim().replace('#', '')
|
||||
const full = h.length === 3 ? h.split('').map((c) => c + c).join('') : h
|
||||
if (full.length < 6) return `rgba(0, 0, 0, ${alpha})`
|
||||
const n = parseInt(full.slice(0, 6), 16)
|
||||
if (Number.isNaN(n)) return `rgba(0, 0, 0, ${alpha})`
|
||||
const r = (n >> 16) & 255
|
||||
const g = (n >> 8) & 255
|
||||
const b = n & 255
|
||||
return `rgba(${r}, ${g}, ${b}, ${alpha})`
|
||||
}
|
||||
|
||||
function computeShadow(p: AnimatableProps): ShadowState | null {
|
||||
const opacity = p.shadowOpacity ?? 0
|
||||
if (opacity <= 0) return null
|
||||
const blur = p.shadowBlur ?? 0
|
||||
const distance = p.shadowDistance ?? 0
|
||||
if (blur <= 0 && distance <= 0) return null
|
||||
const angle = p.shadowAngle ?? 90
|
||||
const rad = (angle * Math.PI) / 180
|
||||
return {
|
||||
sx: Math.cos(rad) * distance,
|
||||
sy: Math.sin(rad) * distance,
|
||||
blur,
|
||||
color: hexToRgba(p.shadowColor ?? '#000000', opacity),
|
||||
}
|
||||
}
|
||||
|
||||
function applyShadow(ctx: CanvasRenderingContext2D, s: ShadowState | null) {
|
||||
if (!s) {
|
||||
ctx.shadowColor = 'transparent'
|
||||
ctx.shadowBlur = 0
|
||||
ctx.shadowOffsetX = 0
|
||||
ctx.shadowOffsetY = 0
|
||||
return
|
||||
}
|
||||
ctx.shadowColor = s.color
|
||||
ctx.shadowBlur = s.blur
|
||||
ctx.shadowOffsetX = s.sx
|
||||
ctx.shadowOffsetY = s.sy
|
||||
}
|
||||
|
||||
function clearShadow(ctx: CanvasRenderingContext2D) {
|
||||
ctx.shadowColor = 'transparent'
|
||||
ctx.shadowBlur = 0
|
||||
ctx.shadowOffsetX = 0
|
||||
ctx.shadowOffsetY = 0
|
||||
}
|
||||
|
||||
function drawLayers(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
layers: Layer[],
|
||||
@@ -44,18 +100,29 @@ function drawLayers(
|
||||
ctx.rotate((p.rotation * Math.PI) / 180)
|
||||
ctx.scale(p.scaleX, p.scaleY)
|
||||
|
||||
const shadow = computeShadow(p)
|
||||
applyShadow(ctx, shadow)
|
||||
|
||||
if (asset.kind === 'rect') {
|
||||
const offX = layer.offsetX ?? asset.width / 2
|
||||
const offY = layer.offsetY ?? asset.height / 2
|
||||
ctx.fillStyle = p.fill ?? asset.fill
|
||||
const fill = p.fill ?? asset.fill
|
||||
const blur = p.blur ?? asset.blur ?? 0
|
||||
ctx.fillStyle = fill
|
||||
if (blur > 0) ctx.filter = `blur(${blur}px)`
|
||||
ctx.fillRect(-offX, -offY, asset.width, asset.height)
|
||||
ctx.filter = 'none'
|
||||
} else if (asset.kind === 'circle') {
|
||||
const offX = layer.offsetX ?? 0
|
||||
const offY = layer.offsetY ?? 0
|
||||
ctx.fillStyle = p.fill ?? asset.fill
|
||||
const fill = p.fill ?? asset.fill
|
||||
const blur = p.blur ?? asset.blur ?? 0
|
||||
ctx.fillStyle = fill
|
||||
if (blur > 0) ctx.filter = `blur(${blur}px)`
|
||||
ctx.beginPath()
|
||||
ctx.arc(-offX, -offY, asset.radius, 0, Math.PI * 2)
|
||||
ctx.fill()
|
||||
ctx.filter = 'none'
|
||||
} else if (asset.kind === 'text') {
|
||||
const offX = layer.offsetX ?? 0
|
||||
const offY = layer.offsetY ?? 0
|
||||
@@ -72,6 +139,7 @@ function drawLayers(
|
||||
}
|
||||
}
|
||||
|
||||
clearShadow(ctx)
|
||||
ctx.restore()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user