canvasengine 1.3.0 → 2.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1137 -0
- package/dist/index.js +3222 -0
- package/dist/index.js.map +1 -0
- package/index.d.ts +4 -0
- package/package.json +43 -17
- package/src/components/Canvas.ts +134 -0
- package/src/components/Container.ts +46 -0
- package/src/components/DisplayObject.ts +458 -0
- package/src/components/Graphic.ts +147 -0
- package/src/components/NineSliceSprite.ts +46 -0
- package/src/components/ParticleEmitter.ts +39 -0
- package/src/components/Scene.ts +6 -0
- package/src/components/Sprite.ts +514 -0
- package/src/components/Text.ts +145 -0
- package/src/components/TilingSprite.ts +39 -0
- package/src/components/Video.ts +110 -0
- package/src/components/Viewport.ts +159 -0
- package/src/components/index.ts +12 -0
- package/src/components/types/DisplayObject.ts +70 -0
- package/src/components/types/MouseEvent.ts +3 -0
- package/src/components/types/Spritesheet.ts +389 -0
- package/src/components/types/index.ts +4 -0
- package/src/directives/Drag.ts +84 -0
- package/src/directives/KeyboardControls.ts +922 -0
- package/src/directives/Scheduler.ts +101 -0
- package/src/directives/Sound.ts +91 -0
- package/src/directives/Transition.ts +45 -0
- package/src/directives/ViewportCull.ts +40 -0
- package/src/directives/ViewportFollow.ts +26 -0
- package/src/directives/index.ts +7 -0
- package/src/engine/animation.ts +149 -0
- package/src/engine/bootstrap.ts +19 -0
- package/src/engine/directive.ts +23 -0
- package/src/engine/reactive.ts +480 -0
- package/src/engine/signal.ts +138 -0
- package/src/engine/trigger.ts +96 -0
- package/src/engine/utils.ts +211 -0
- package/src/hooks/addContext.ts +6 -0
- package/src/hooks/useProps.ts +155 -0
- package/src/hooks/useRef.ts +21 -0
- package/src/index.ts +15 -0
- package/src/utils/Ease.ts +33 -0
- package/src/utils/RadialGradient.ts +115 -0
- package/testing/index.ts +11 -0
- package/.gitattributes +0 -22
- package/.npmignore +0 -163
- package/canvasengine-1.3.0.all.min.js +0 -21
- package/canvasengine.js +0 -5802
- package/core/DB.js +0 -24
- package/core/ModelServer.js +0 -348
- package/core/Users.js +0 -190
- package/core/engine-common.js +0 -952
- package/doc/cocoonjs.md +0 -36
- package/doc/doc-lang.yml +0 -43
- package/doc/doc-router.yml +0 -14
- package/doc/doc-tuto.yml +0 -9
- package/doc/doc.yml +0 -39
- package/doc/element.md +0 -37
- package/doc/entity.md +0 -90
- package/doc/extend.md +0 -47
- package/doc/get_started.md +0 -19
- package/doc/images/entity.png +0 -0
- package/doc/multitouch.md +0 -58
- package/doc/nodejs.md +0 -142
- package/doc/scene.md +0 -44
- package/doc/text.md +0 -156
- package/examples/server/client.html +0 -31
- package/examples/server/server.js +0 -16
- package/examples/tiled_server/client.html +0 -52
- package/examples/tiled_server/images/tiles_spritesheet.png +0 -0
- package/examples/tiled_server/server/map.json +0 -50
- package/examples/tiled_server/server/map.tmx +0 -16
- package/examples/tiled_server/server/server.js +0 -16
- package/extends/Animation.js +0 -910
- package/extends/Effect.js +0 -252
- package/extends/Gleed2d.js +0 -252
- package/extends/Hit.js +0 -1509
- package/extends/Input.js +0 -699
- package/extends/Marshal.js +0 -716
- package/extends/Scrolling.js +0 -388
- package/extends/Soundmanager2.js +0 -5466
- package/extends/Spritesheet.js +0 -196
- package/extends/Text.js +0 -366
- package/extends/Tiled.js +0 -403
- package/extends/Window.js +0 -575
- package/extends/gamepad.js +0 -397
- package/extends/socket.io.min.js +0 -2
- package/extends/swf/soundmanager2.swf +0 -0
- package/extends/swf/soundmanager2_debug.swf +0 -0
- package/extends/swf/soundmanager2_flash9.swf +0 -0
- package/extends/swf/soundmanager2_flash9_debug.swf +0 -0
- package/extends/swf/soundmanager2_flash_xdomain.zip +0 -0
- package/extends/workers/transition.js +0 -43
- package/index.js +0 -46
- package/license.txt +0 -19
- package/readme.md +0 -483
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { ObservablePoint } from "pixi.js"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if code is running in a browser environment
|
|
5
|
+
* @returns {boolean} True if running in browser, false otherwise
|
|
6
|
+
*/
|
|
7
|
+
export function isBrowser(): boolean {
|
|
8
|
+
return typeof window !== 'undefined'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns current high-resolution timestamp
|
|
13
|
+
* @returns {number} Current time in milliseconds
|
|
14
|
+
*/
|
|
15
|
+
export function preciseNow(): number {
|
|
16
|
+
return typeof performance !== 'undefined' ? performance.now() : Date.now()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Converts frames per second to milliseconds
|
|
21
|
+
* @param {number} fps - Frames per second
|
|
22
|
+
* @returns {number} Milliseconds per frame
|
|
23
|
+
*/
|
|
24
|
+
export function fps2ms(fps: number): number {
|
|
25
|
+
return 1000 / fps
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Checks if a value is a Promise
|
|
30
|
+
* @param {any} value - Value to check
|
|
31
|
+
* @returns {boolean} True if value is a Promise, false otherwise
|
|
32
|
+
*/
|
|
33
|
+
export function isPromise(value: any): boolean {
|
|
34
|
+
return value && value instanceof Promise
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function arrayEquals(a: any[], b: any[]): boolean {
|
|
38
|
+
if (a.length !== b.length) return false;
|
|
39
|
+
for (let i = 0; i < a.length; i++) {
|
|
40
|
+
const v = a[i];
|
|
41
|
+
const bv = b[i];
|
|
42
|
+
if (typeof v === 'object' && v !== null) {
|
|
43
|
+
if (typeof bv !== 'object' || bv === null) return false;
|
|
44
|
+
if (Array.isArray(v)) {
|
|
45
|
+
if (!Array.isArray(bv) || !arrayEquals(v, bv)) return false;
|
|
46
|
+
} else if (!objectEquals(v, bv)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
} else if (v !== bv) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function objectEquals(a: object, b: object): boolean {
|
|
57
|
+
const keysA = Object.keys(a);
|
|
58
|
+
const keysB = Object.keys(b);
|
|
59
|
+
if (keysA.length !== keysB.length) return false;
|
|
60
|
+
for (let key of keysA) {
|
|
61
|
+
if (!b.hasOwnProperty(key)) return false;
|
|
62
|
+
if (!deepEquals(a[key], b[key])) return false;
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function deepEquals(a: any, b: any): boolean {
|
|
68
|
+
if (a === b) return true;
|
|
69
|
+
if (typeof a !== typeof b) return false;
|
|
70
|
+
if (typeof a === 'object' && a !== null) {
|
|
71
|
+
if (Array.isArray(a)) {
|
|
72
|
+
return Array.isArray(b) && arrayEquals(a, b);
|
|
73
|
+
}
|
|
74
|
+
return objectEquals(a, b);
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Checks if a value is a function
|
|
81
|
+
* @param {unknown} val - Value to check
|
|
82
|
+
* @returns {boolean} True if value is a function, false otherwise
|
|
83
|
+
*/
|
|
84
|
+
export function isFunction(val: unknown): boolean {
|
|
85
|
+
return {}.toString.call(val) === '[object Function]'
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Checks if a value is a plain object
|
|
90
|
+
* @param {unknown} val - Value to check
|
|
91
|
+
* @returns {boolean} True if value is an object (not null and not array), false otherwise
|
|
92
|
+
*/
|
|
93
|
+
export function isObject(val: unknown): boolean {
|
|
94
|
+
return typeof val == 'object' && val != null && !Array.isArray(val)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Sets a value in an object using a dot notation path
|
|
99
|
+
* @param {Record<string, any>} obj - Target object
|
|
100
|
+
* @param {string | string[]} path - Path to set value at (e.g., 'a.b.c' or ['a', 'b', 'c'])
|
|
101
|
+
* @param {any} value - Value to set
|
|
102
|
+
* @param {boolean} onlyPlainObject - If true, only creates plain objects in path
|
|
103
|
+
* @returns {Record<string, any>} Modified object
|
|
104
|
+
*/
|
|
105
|
+
export function set(
|
|
106
|
+
obj: Record<string, any>,
|
|
107
|
+
path: string | string[],
|
|
108
|
+
value: any,
|
|
109
|
+
onlyPlainObject = false
|
|
110
|
+
): Record<string, any> {
|
|
111
|
+
if (Object(obj) !== obj) return obj;
|
|
112
|
+
|
|
113
|
+
if (typeof path === 'string') {
|
|
114
|
+
path = path.split('.');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let len = path.length;
|
|
118
|
+
if (!len) return obj;
|
|
119
|
+
|
|
120
|
+
let current = obj;
|
|
121
|
+
for (let i = 0; i < len - 1; i++) {
|
|
122
|
+
let segment = path[i];
|
|
123
|
+
let nextSegment: number | string = path[i + 1];
|
|
124
|
+
let isNextNumeric = !isNaN(Number(nextSegment)) && isFinite(Number(nextSegment));
|
|
125
|
+
|
|
126
|
+
if (!current[segment] || typeof current[segment] !== 'object') {
|
|
127
|
+
current[segment] = (isNextNumeric && !onlyPlainObject) ? [] : {};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
current = current[segment];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
current[path[len - 1]] = value;
|
|
134
|
+
|
|
135
|
+
return obj;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Gets a value from an object using a dot notation path
|
|
140
|
+
* @param {Record<string, any>} obj - Source object
|
|
141
|
+
* @param {string} path - Path to get value from (e.g., 'a.b.c')
|
|
142
|
+
* @returns {any} Value at path or undefined if not found
|
|
143
|
+
*/
|
|
144
|
+
export function get(obj: Record<string, any>, path: string): any {
|
|
145
|
+
const keys = path.split('.');
|
|
146
|
+
let current = obj;
|
|
147
|
+
|
|
148
|
+
for (let key of keys) {
|
|
149
|
+
if (current[key] === undefined) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
current = current[key];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return current;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Logs a message to console
|
|
160
|
+
* @param {any} text - Message to log
|
|
161
|
+
*/
|
|
162
|
+
export function log(text: any): void {
|
|
163
|
+
console.log(text)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Logs an error message to console
|
|
168
|
+
* @param {any} text - Error message to log
|
|
169
|
+
*/
|
|
170
|
+
export function error(text: any): void {
|
|
171
|
+
console.error(text)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Sets the position of an ObservablePoint using various input formats
|
|
176
|
+
* @param {ObservablePoint} observablePoint - The point to modify
|
|
177
|
+
* @param {Object | number | [number, number]} point - New position value
|
|
178
|
+
*/
|
|
179
|
+
export function setObservablePoint(
|
|
180
|
+
observablePoint: ObservablePoint,
|
|
181
|
+
point: { x: number, y: number } | number | [number, number]
|
|
182
|
+
): void {
|
|
183
|
+
if (typeof point === 'number') {
|
|
184
|
+
observablePoint.set(point);
|
|
185
|
+
}
|
|
186
|
+
else if (Array.isArray(point)) {
|
|
187
|
+
observablePoint.set(point[0], point[1]);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
observablePoint.set(point.x, point.y);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Calculates the Euclidean distance between two points
|
|
196
|
+
* @param {number} x1 - X coordinate of first point
|
|
197
|
+
* @param {number} y1 - Y coordinate of first point
|
|
198
|
+
* @param {number} x2 - X coordinate of second point
|
|
199
|
+
* @param {number} y2 - Y coordinate of second point
|
|
200
|
+
* @returns {number} Distance between the points
|
|
201
|
+
*/
|
|
202
|
+
export function calculateDistance(
|
|
203
|
+
x1: number,
|
|
204
|
+
y1: number,
|
|
205
|
+
x2: number,
|
|
206
|
+
y2: number
|
|
207
|
+
): number {
|
|
208
|
+
const dx = x1 - x2;
|
|
209
|
+
const dy = y1 - y2;
|
|
210
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
211
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { isSignal, signal } from "@signe/reactive"
|
|
2
|
+
import { isPrimitive } from "../engine/reactive"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Converts props into reactive signals if they are primitive values.
|
|
6
|
+
*
|
|
7
|
+
* @param {object} props - The properties to convert.
|
|
8
|
+
* @param {object} [defaults={}] - Default values for properties.
|
|
9
|
+
* @returns {object} An object with reactive signals.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const props = useProps({ count: 0, name: "John" });
|
|
13
|
+
* console.log(props.count()); // 0
|
|
14
|
+
* props.count.set(1);
|
|
15
|
+
* console.log(props.count()); // 1
|
|
16
|
+
*/
|
|
17
|
+
export const useProps = (props, defaults = {}): any => {
|
|
18
|
+
if (isSignal(props)) {
|
|
19
|
+
return props()
|
|
20
|
+
}
|
|
21
|
+
const obj = {}
|
|
22
|
+
for (let key in props) {
|
|
23
|
+
const value = props[key]
|
|
24
|
+
obj[key] = isPrimitive(value) ? signal(value) : value
|
|
25
|
+
}
|
|
26
|
+
for (let key in defaults) {
|
|
27
|
+
if (!(key in obj)) {
|
|
28
|
+
obj[key] = signal(defaults[key])
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return obj
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type PropType = NumberConstructor | StringConstructor | BooleanConstructor |
|
|
35
|
+
FunctionConstructor | ObjectConstructor | ArrayConstructor |
|
|
36
|
+
null | (new (...args: any[]) => any);
|
|
37
|
+
|
|
38
|
+
interface PropConfig {
|
|
39
|
+
type?: PropType | PropType[];
|
|
40
|
+
required?: boolean;
|
|
41
|
+
default?: any | ((props: any) => any);
|
|
42
|
+
validator?: (value: any, props: any) => boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type PropSchema = {
|
|
46
|
+
[key: string]: PropType | PropType[] | PropConfig;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validates and defines properties based on a schema.
|
|
51
|
+
*
|
|
52
|
+
* @param {object} props - The properties to validate.
|
|
53
|
+
* @returns {function} A function that takes a schema and returns validated properties.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* const schema = {
|
|
57
|
+
* age: { type: Number, required: true },
|
|
58
|
+
* name: { type: String, default: "Anonymous" }
|
|
59
|
+
* };
|
|
60
|
+
* const validatedProps = useDefineProps({ age: 25 })(schema);
|
|
61
|
+
* console.log(validatedProps.age()); // 25
|
|
62
|
+
* console.log(validatedProps.name()); // "Anonymous"
|
|
63
|
+
*/
|
|
64
|
+
export const useDefineProps = (props: any) => {
|
|
65
|
+
return (schema?: PropSchema) => {
|
|
66
|
+
const rawProps = isSignal(props) ? props() : props
|
|
67
|
+
const validatedProps: { [key: string]: any } = {}
|
|
68
|
+
|
|
69
|
+
for (const key in schema) {
|
|
70
|
+
const propConfig = schema[key]
|
|
71
|
+
const value = rawProps[key]
|
|
72
|
+
let validatedValue: any
|
|
73
|
+
|
|
74
|
+
// Handle simple type definition
|
|
75
|
+
if (typeof propConfig === 'function') {
|
|
76
|
+
validateType(key, value, [propConfig])
|
|
77
|
+
validatedValue = value
|
|
78
|
+
}
|
|
79
|
+
// Handle array of types
|
|
80
|
+
else if (Array.isArray(propConfig)) {
|
|
81
|
+
validateType(key, value, propConfig)
|
|
82
|
+
validatedValue = value
|
|
83
|
+
}
|
|
84
|
+
// Handle detailed configuration object
|
|
85
|
+
else if (propConfig && typeof propConfig === 'object') {
|
|
86
|
+
// Check required prop
|
|
87
|
+
if (propConfig.required && value === undefined) {
|
|
88
|
+
throw new Error(`Missing required prop: ${key}`)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Validate type if specified
|
|
92
|
+
if (propConfig.type) {
|
|
93
|
+
const types = Array.isArray(propConfig.type) ? propConfig.type : [propConfig.type]
|
|
94
|
+
validateType(key, value, types)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Run custom validator if provided
|
|
98
|
+
if (propConfig.validator && !propConfig.validator(value, rawProps)) {
|
|
99
|
+
throw new Error(`Invalid prop: custom validation failed for prop "${key}"`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Set default value if value is undefined
|
|
103
|
+
if (value === undefined && 'default' in propConfig) {
|
|
104
|
+
validatedValue = typeof propConfig.default === 'function'
|
|
105
|
+
? propConfig.default(rawProps)
|
|
106
|
+
: propConfig.default
|
|
107
|
+
} else {
|
|
108
|
+
validatedValue = value
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
validatedProps[key] = isSignal(validatedValue)
|
|
113
|
+
? validatedValue
|
|
114
|
+
: signal(validatedValue)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
...useProps(rawProps),
|
|
119
|
+
...validatedProps
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Validates the type of a property.
|
|
126
|
+
*
|
|
127
|
+
* @param {string} key - The property key.
|
|
128
|
+
* @param {any} value - The property value.
|
|
129
|
+
* @param {any[]} types - The expected types.
|
|
130
|
+
* @throws Will throw an error if the type check fails.
|
|
131
|
+
*/
|
|
132
|
+
function validateType(key: string, value: any, types: any[]) {
|
|
133
|
+
if (value === undefined || value === null) return
|
|
134
|
+
|
|
135
|
+
// Si c'est un signal, on vérifie la valeur du signal
|
|
136
|
+
const valueToCheck = isSignal(value) ? value() : value
|
|
137
|
+
|
|
138
|
+
const valid = types.some(type => {
|
|
139
|
+
if (type === Number) return typeof valueToCheck === 'number'
|
|
140
|
+
if (type === String) return typeof valueToCheck === 'string'
|
|
141
|
+
if (type === Boolean) return typeof valueToCheck === 'boolean'
|
|
142
|
+
if (type === Function) return typeof valueToCheck === 'function'
|
|
143
|
+
if (type === Object) return typeof valueToCheck === 'object'
|
|
144
|
+
if (type === Array) return Array.isArray(valueToCheck)
|
|
145
|
+
if (type === null) return valueToCheck === null
|
|
146
|
+
return valueToCheck instanceof type
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
if (!valid) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`Invalid prop: type check failed for prop "${key}". ` +
|
|
152
|
+
`Expected ${types.map(t => t.name).join(' or ')}`
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Element } from "../engine/reactive";
|
|
2
|
+
import { ComponentInstance } from "../components/DisplayObject";
|
|
3
|
+
|
|
4
|
+
export function useRef(element: Element<ComponentInstance>, ref: string): Element<ComponentInstance> | null {
|
|
5
|
+
const { props } = element;
|
|
6
|
+
if (props.ref == ref) {
|
|
7
|
+
return element;
|
|
8
|
+
}
|
|
9
|
+
// Recursive search for the component with the given id
|
|
10
|
+
if (props.children) {
|
|
11
|
+
for (const child of props.children) {
|
|
12
|
+
const result = useRef(child, ref);
|
|
13
|
+
if (result) {
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// If not found, return undefined
|
|
20
|
+
return null;
|
|
21
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import './directives'
|
|
2
|
+
export * from '@signe/reactive'
|
|
3
|
+
export { Howler } from 'howler'
|
|
4
|
+
export * from './components'
|
|
5
|
+
export * from './engine/reactive'
|
|
6
|
+
export * from './engine/signal'
|
|
7
|
+
export * from './engine/trigger'
|
|
8
|
+
export * from './engine/bootstrap'
|
|
9
|
+
export * from './engine/animation'
|
|
10
|
+
export { useProps, useDefineProps } from './hooks/useProps'
|
|
11
|
+
export * from './utils/Ease'
|
|
12
|
+
export * from './utils/RadialGradient'
|
|
13
|
+
export * from './components/DisplayObject'
|
|
14
|
+
export { isObservable } from 'rxjs'
|
|
15
|
+
export * as Utils from './engine/utils'
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
linear,
|
|
3
|
+
easeIn,
|
|
4
|
+
easeInOut,
|
|
5
|
+
easeOut,
|
|
6
|
+
circIn,
|
|
7
|
+
circInOut,
|
|
8
|
+
circOut,
|
|
9
|
+
backIn,
|
|
10
|
+
backInOut,
|
|
11
|
+
backOut,
|
|
12
|
+
anticipate,
|
|
13
|
+
bounceIn,
|
|
14
|
+
bounceInOut,
|
|
15
|
+
bounceOut
|
|
16
|
+
} from "popmotion"
|
|
17
|
+
|
|
18
|
+
export const Easing = {
|
|
19
|
+
linear,
|
|
20
|
+
easeIn,
|
|
21
|
+
easeInOut,
|
|
22
|
+
easeOut,
|
|
23
|
+
circIn,
|
|
24
|
+
circInOut,
|
|
25
|
+
circOut,
|
|
26
|
+
backIn,
|
|
27
|
+
backInOut,
|
|
28
|
+
backOut,
|
|
29
|
+
anticipate,
|
|
30
|
+
bounceIn,
|
|
31
|
+
bounceInOut,
|
|
32
|
+
bounceOut
|
|
33
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Texture, ImageSource, DOMAdapter, Matrix } from "pixi.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a radial gradient texture that can be used in PixiJS.
|
|
5
|
+
* @example
|
|
6
|
+
* const gradient = new RadialGradient(size, size, 0, size, size, 0);
|
|
7
|
+
* gradient.addColorStop(0, "rgba(255, 255, 0, 1)");
|
|
8
|
+
* gradient.addColorStop(0.5, "rgba(255, 255, 0, 0.3)");
|
|
9
|
+
* gradient.addColorStop(0.8, "rgba(255, 255, 0, 0)");
|
|
10
|
+
*/
|
|
11
|
+
export class RadialGradient {
|
|
12
|
+
private canvas: HTMLCanvasElement;
|
|
13
|
+
private ctx: CanvasRenderingContext2D | null;
|
|
14
|
+
private gradient: CanvasGradient | null = null;
|
|
15
|
+
private texture: Texture | null = null;
|
|
16
|
+
public transform: Matrix;
|
|
17
|
+
|
|
18
|
+
public size = 600;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new RadialGradient instance
|
|
22
|
+
* @param x0 - The x-coordinate of the starting circle
|
|
23
|
+
* @param y0 - The y-coordinate of the starting circle
|
|
24
|
+
* @param x1 - The x-coordinate of the ending circle
|
|
25
|
+
* @param y1 - The y-coordinate of the ending circle
|
|
26
|
+
* @param x2 - The x-coordinate for gradient transformation
|
|
27
|
+
* @param y2 - The y-coordinate for gradient transformation
|
|
28
|
+
* @param focalPoint - The focal point of the gradient (0-1), defaults to 0
|
|
29
|
+
*/
|
|
30
|
+
constructor(
|
|
31
|
+
private x0: number,
|
|
32
|
+
private y0: number,
|
|
33
|
+
private x1: number,
|
|
34
|
+
private y1: number,
|
|
35
|
+
private x2: number,
|
|
36
|
+
private y2: number,
|
|
37
|
+
private focalPoint: number = 0
|
|
38
|
+
) {
|
|
39
|
+
this.size = x0;
|
|
40
|
+
const halfSize = this.size * 0.5;
|
|
41
|
+
|
|
42
|
+
this.canvas = DOMAdapter.get().createCanvas() as any;
|
|
43
|
+
this.canvas.width = this.size;
|
|
44
|
+
this.canvas.height = this.size;
|
|
45
|
+
this.ctx = this.canvas.getContext("2d");
|
|
46
|
+
|
|
47
|
+
if (this.ctx) {
|
|
48
|
+
this.gradient = this.ctx.createRadialGradient(
|
|
49
|
+
halfSize * (1 - focalPoint),
|
|
50
|
+
halfSize,
|
|
51
|
+
0,
|
|
52
|
+
halfSize,
|
|
53
|
+
halfSize,
|
|
54
|
+
halfSize - 0.5
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Adds a color stop to the gradient
|
|
61
|
+
* @param offset - The position of the color stop (0-1)
|
|
62
|
+
* @param color - The color value (any valid CSS color string)
|
|
63
|
+
*/
|
|
64
|
+
addColorStop(offset: number, color: string) {
|
|
65
|
+
if (this.gradient) {
|
|
66
|
+
this.gradient.addColorStop(offset, color);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Renders the gradient and returns the texture with its transformation matrix
|
|
72
|
+
* @param options - Render options
|
|
73
|
+
* @param options.translate - Optional translation coordinates
|
|
74
|
+
* @returns Object containing the texture and transformation matrix
|
|
75
|
+
*/
|
|
76
|
+
render({ translate }: { translate?: { x: number; y: number } } = {}) {
|
|
77
|
+
const { x0, y0, x1, y1, x2, y2, focalPoint } = this;
|
|
78
|
+
const defaultSize = this.size;
|
|
79
|
+
if (this.ctx && this.gradient) {
|
|
80
|
+
this.ctx.fillStyle = this.gradient;
|
|
81
|
+
this.ctx.fillRect(0, 0, defaultSize, defaultSize);
|
|
82
|
+
|
|
83
|
+
this.texture = new Texture({
|
|
84
|
+
source: new ImageSource({
|
|
85
|
+
resource: this.canvas,
|
|
86
|
+
addressModeU: "clamp-to-edge",
|
|
87
|
+
addressModeV: "clamp-to-edge",
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const m = new Matrix();
|
|
92
|
+
const dx = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
|
|
93
|
+
const dy = Math.sqrt((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0));
|
|
94
|
+
const angle = Math.atan2(y1 - y0, x1 - x0);
|
|
95
|
+
|
|
96
|
+
// Calculate the scale factors correctly
|
|
97
|
+
const scaleX = dx / defaultSize;
|
|
98
|
+
const scaleY = dy / defaultSize;
|
|
99
|
+
|
|
100
|
+
// Apply transformations in the correct order
|
|
101
|
+
m.rotate(-angle);
|
|
102
|
+
m.scale(scaleX, scaleY);
|
|
103
|
+
if (translate) {
|
|
104
|
+
m.translate(translate.x, translate.y);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.transform = m;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
texture: this.texture,
|
|
112
|
+
matrix: this.transform,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
package/testing/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { bootstrapCanvas, Canvas, ComponentInstance, Element, h } from "canvasengine";
|
|
2
|
+
|
|
3
|
+
export class TestBed {
|
|
4
|
+
static async createComponent(component: any, props: any = {}, children: any = []): Promise<Element<ComponentInstance>> {
|
|
5
|
+
const comp = () => h(Canvas, {
|
|
6
|
+
tickStart: false
|
|
7
|
+
}, h(component, props, children))
|
|
8
|
+
const canvas = await bootstrapCanvas(document.getElementById('root'), comp)
|
|
9
|
+
return canvas.props.children?.[0]
|
|
10
|
+
}
|
|
11
|
+
}
|
package/.gitattributes
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# Auto detect text files and perform LF normalization
|
|
2
|
-
* text=auto
|
|
3
|
-
|
|
4
|
-
# Custom for Visual Studio
|
|
5
|
-
*.cs diff=csharp
|
|
6
|
-
*.sln merge=union
|
|
7
|
-
*.csproj merge=union
|
|
8
|
-
*.vbproj merge=union
|
|
9
|
-
*.fsproj merge=union
|
|
10
|
-
*.dbproj merge=union
|
|
11
|
-
|
|
12
|
-
# Standard to msysgit
|
|
13
|
-
*.doc diff=astextplain
|
|
14
|
-
*.DOC diff=astextplain
|
|
15
|
-
*.docx diff=astextplain
|
|
16
|
-
*.DOCX diff=astextplain
|
|
17
|
-
*.dot diff=astextplain
|
|
18
|
-
*.DOT diff=astextplain
|
|
19
|
-
*.pdf diff=astextplain
|
|
20
|
-
*.PDF diff=astextplain
|
|
21
|
-
*.rtf diff=astextplain
|
|
22
|
-
*.RTF diff=astextplain
|