Compare commits
	
		
			6 Commits
		
	
	
		
			938d5041e4
			...
			5ac9cb442a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5ac9cb442a | |||
| e08a3ec6b5 | |||
| 586c7b959d | |||
| 045a0377ee | |||
| 6ee85aff1b | |||
| 0eb0b6f7f5 | 
							
								
								
									
										1960
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1960
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -39,6 +39,7 @@ | ||||
|     "webpack-dev-server": "^4.7.2" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@fluentui/react": "^8.56.0", | ||||
|     "@juggle/resize-observer": "^3.3.1", | ||||
|     "gl-matrix": "^3.4.3", | ||||
|     "react": "^17.0.2", | ||||
|  | ||||
							
								
								
									
										3
									
								
								source/Component/HeaderBar/HeaderBar.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								source/Component/HeaderBar/HeaderBar.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| div.header-bar { | ||||
|     display: flex; | ||||
| } | ||||
							
								
								
									
										40
									
								
								source/Component/HeaderBar/HeaderBar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								source/Component/HeaderBar/HeaderBar.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| import { Component, ReactNode } from "react"; | ||||
| import { useStatus, IMixinStatusProps } from "@Context/Status"; | ||||
| import { Theme, BackgroundLevel, FontLevel } from "@Component/Theme/Theme"; | ||||
| 
 | ||||
| interface IHeaderBarProps { | ||||
|     height: number; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 头部信息栏 | ||||
|  */ | ||||
| @useStatus | ||||
| class HeaderBar extends Component<IHeaderBarProps & IMixinStatusProps> { | ||||
| 
 | ||||
|     private changeListener = () => { | ||||
|         this.forceUpdate(); | ||||
|     } | ||||
| 
 | ||||
|     public componentDidMount() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public componentWillUnmount() { | ||||
|          | ||||
|     } | ||||
| 
 | ||||
|     public render(): ReactNode { | ||||
|         return <Theme | ||||
|             className="header-bar" | ||||
|             backgroundLevel={BackgroundLevel.Level1} | ||||
|             fontLevel={FontLevel.Level3} | ||||
|             style={{ height: this.props.height }} | ||||
|         > | ||||
|             Living Together | Web | ||||
|         </Theme> | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export default HeaderBar; | ||||
| export { HeaderBar }; | ||||
							
								
								
									
										7
									
								
								source/Component/Localization/Localization.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								source/Component/Localization/Localization.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| span.ZH_CN { | ||||
|     font-family: 'Microsoft Yahei', Verdana, Simsun, 'Segoe UI', Tahoma, Arial, sans-serif; | ||||
| } | ||||
| 
 | ||||
| span.EN_US { | ||||
|     font-family: 'Segoe UI Web Regular', 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif; | ||||
| } | ||||
							
								
								
									
										70
									
								
								source/Component/Localization/Localization.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								source/Component/Localization/Localization.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| import { Component, ReactNode, DetailedHTMLProps, HTMLAttributes } from "react"; | ||||
| import { useSetting, IMixinSettingProps, Language } from "@Context/Setting"; | ||||
| import "./Localization.scss"; | ||||
| 
 | ||||
| import EN_US from "../../Localization/EN-US"; | ||||
| import ZH_CN from "../../Localization/ZH-CN"; | ||||
| 
 | ||||
| const LanguageDataBase = { | ||||
|     EN_US, ZH_CN | ||||
| } | ||||
| 
 | ||||
| interface ILocalizationProps { | ||||
|     className?: string; | ||||
|     i18nKey: keyof typeof EN_US; | ||||
|     options?: Record<string, string>; | ||||
| } | ||||
| 
 | ||||
| function I18N(language: Language, key: keyof typeof EN_US, values?: Record<string, string>) { | ||||
|     let i18nValue = LanguageDataBase[language][key]; | ||||
|     if (values) { | ||||
|         for (let valueKey in values) { | ||||
|             i18nValue = i18nValue.replaceAll(new RegExp(`\\{\\s*${valueKey}\\s*\\}`, "g"), values[valueKey]); | ||||
|         } | ||||
|     } | ||||
|     return i18nValue; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 本地化组件 | ||||
|  */ | ||||
| @useSetting | ||||
| class Localization extends Component<ILocalizationProps & IMixinSettingProps &  | ||||
|     DetailedHTMLProps< | ||||
|         HTMLAttributes<HTMLSpanElement>, HTMLSpanElement | ||||
|     > | ||||
| > { | ||||
| 
 | ||||
|     private handelLanguageChange = () => { | ||||
|         this.forceUpdate(); | ||||
|     } | ||||
| 
 | ||||
|     public componentDidMount() { | ||||
|         if (this.props.setting) { | ||||
|             this.props.setting.on("language", this.handelLanguageChange); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public componentWillUnmount() { | ||||
|         if (this.props.setting) { | ||||
|             this.props.setting.off("language", this.handelLanguageChange); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public render(): ReactNode { | ||||
|         let language: Language = this.props.setting ? this.props.setting.language : "EN_US"; | ||||
|         let classNameList: string[] = []; | ||||
|         if (this.props.className) classNameList.push(this.props.className); | ||||
|         classNameList.push(language); | ||||
|         let safeProps = {...this.props}; | ||||
|         delete safeProps.className; | ||||
|         delete safeProps.setting; | ||||
|         delete (safeProps as any).i18nKey; | ||||
|         delete safeProps.options; | ||||
|         return <span {...safeProps} className={classNameList.join(" ")}> | ||||
|             {I18N(language, this.props.i18nKey, this.props.options)} | ||||
|         </span> | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export { Localization, I18N }; | ||||
							
								
								
									
										80
									
								
								source/Component/Theme/Theme.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								source/Component/Theme/Theme.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | ||||
| @import "@fluentui/react/dist/sass/References"; | ||||
| 
 | ||||
| $lt-font-size-normal: $ms-font-size-14; | ||||
| $lt-font-size-lvl3: $ms-font-size-16; | ||||
| $lt-font-size-lvl2: $ms-font-size-18; | ||||
| $lt-font-size-lvl1: $ms-font-size-24; | ||||
| 
 | ||||
| $lt-font-weight-normal: $ms-font-weight-regular; | ||||
| $lt-font-weight-lvl3: $ms-font-weight-semibold; | ||||
| $lt-font-weight-lvl2: $ms-font-weight-semibold; | ||||
| $lt-font-weight-lvl1: $ms-font-weight-bold; | ||||
| 
 | ||||
| // 背景颜色 | ||||
| $lt-bg-color-lvl1-dark: $ms-color-gray140; | ||||
| $lt-bg-color-lvl2-dark: $ms-color-gray150; | ||||
| $lt-bg-color-lvl3-dark: $ms-color-gray160; | ||||
| $lt-bg-color-lvl4-dark: $ms-color-gray180; | ||||
| $lt-bg-color-lvl5-dark: $ms-color-gray200; | ||||
| 
 | ||||
| // 文字颜色 | ||||
| $lt-font-color-normal-dark: $ms-color-gray110; | ||||
| $lt-font-color-lvl3-dark: $ms-color-gray100; | ||||
| $lt-font-color-lvl2-dark: $ms-color-gray100; | ||||
| $lt-font-color-lvl1-dark: $ms-color-gray90; | ||||
| 
 | ||||
| // 背景颜色 | ||||
| $lt-bg-color-lvl1-light: $ms-color-gray10; | ||||
| $lt-bg-color-lvl2-light: $ms-color-gray20; | ||||
| $lt-bg-color-lvl3-light: $ms-color-gray30; | ||||
| $lt-bg-color-lvl4-light: $ms-color-gray50; | ||||
| $lt-bg-color-lvl5-light: $ms-color-gray70; | ||||
| 
 | ||||
| // 文字颜色 | ||||
| $lt-font-color-normal-light: $ms-color-gray130; | ||||
| $lt-font-color-lvl3-light: $ms-color-gray140; | ||||
| $lt-font-color-lvl2-light: $ms-color-gray140; | ||||
| $lt-font-color-lvl1-light: $ms-color-gray150; | ||||
| 
 | ||||
| div.dark, div.light { | ||||
|     transition: all 300ms ease-in-out; | ||||
| } | ||||
| 
 | ||||
| div.dark.background-lvl1 { background-color: $lt-bg-color-lvl1-dark; } | ||||
| div.dark.background-lvl2 { background-color: $lt-bg-color-lvl2-dark; } | ||||
| div.dark.background-lvl3 { background-color: $lt-bg-color-lvl3-dark; } | ||||
| div.dark.background-lvl4 { background-color: $lt-bg-color-lvl4-dark; } | ||||
| div.dark.background-lvl5 { background-color: $lt-bg-color-lvl5-dark; } | ||||
| 
 | ||||
| div.light.background-lvl1 { background-color: $lt-bg-color-lvl1-light; } | ||||
| div.light.background-lvl2 { background-color: $lt-bg-color-lvl2-light; } | ||||
| div.light.background-lvl3 { background-color: $lt-bg-color-lvl3-light; } | ||||
| div.light.background-lvl4 { background-color: $lt-bg-color-lvl4-light; } | ||||
| div.light.background-lvl5 { background-color: $lt-bg-color-lvl5-light; } | ||||
| 
 | ||||
| div.font-normal { | ||||
|     font-size: $lt-font-size-normal; | ||||
|     font-weight: $lt-font-weight-normal; | ||||
| } | ||||
| div.font-lvl3 { | ||||
|     font-size: $lt-font-size-lvl3; | ||||
|     font-weight: $lt-font-weight-lvl3; | ||||
| } | ||||
| div.font-lvl2 { | ||||
|     font-size: $lt-font-size-lvl2; | ||||
|     font-weight: $lt-font-weight-lvl2; | ||||
| } | ||||
| div.font-lvl1 { | ||||
|     font-size: $lt-font-size-lvl1; | ||||
|     font-weight: $lt-font-weight-lvl1; | ||||
| } | ||||
| 
 | ||||
| div.dark.font-normal { color: $lt-font-color-normal-dark; } | ||||
| div.dark.font-lvl3 { color: $lt-font-color-lvl3-dark; } | ||||
| div.dark.font-lvl2 { color: $lt-font-color-lvl2-dark; } | ||||
| div.dark.font-lvl1 { color: $lt-font-color-lvl1-dark; } | ||||
| 
 | ||||
| div.light.font-normal { color: $lt-font-color-normal-light; } | ||||
| div.light.font-lvl3 { color: $lt-font-color-lvl3-light; } | ||||
| div.light.font-lvl2 { color: $lt-font-color-lvl2-light; } | ||||
| div.light.font-lvl1 { color: $lt-font-color-lvl1-light; } | ||||
							
								
								
									
										85
									
								
								source/Component/Theme/Theme.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								source/Component/Theme/Theme.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| import { useSetting, Themes, IMixinSettingProps } from "@Context/Setting"; | ||||
| import { Component, ReactNode, DetailedHTMLProps, HTMLAttributes } from "react"; | ||||
| import "./Theme.scss"; | ||||
| 
 | ||||
| enum FontLevel { | ||||
|     normal = "normal", | ||||
|     Level3 = "lvl3", | ||||
|     Level2 = "lvl2", | ||||
|     Level1 = "lvl1" | ||||
| } | ||||
| 
 | ||||
| enum BackgroundLevel { | ||||
|     Level5 = "lvl5", | ||||
|     Level4 = "lvl4", | ||||
|     Level3 = "lvl3", | ||||
|     Level2 = "lvl2", | ||||
|     Level1 = "lvl1" | ||||
| } | ||||
| 
 | ||||
| interface IThemeProps { | ||||
|     className?: string; | ||||
|     fontLevel?: FontLevel; | ||||
|     backgroundLevel?: BackgroundLevel; | ||||
| }  | ||||
| 
 | ||||
| /** | ||||
|  * 主题切换 | ||||
|  */ | ||||
| @useSetting | ||||
| class Theme extends Component< | ||||
|     IThemeProps & IMixinSettingProps & DetailedHTMLProps< | ||||
|         HTMLAttributes<HTMLDivElement>, HTMLDivElement | ||||
|     > | ||||
| > { | ||||
| 
 | ||||
|     private handelThemeChange = () => { | ||||
|         this.forceUpdate(); | ||||
|     } | ||||
| 
 | ||||
|     public componentDidMount() { | ||||
|         if (this.props.setting) { | ||||
|             this.props.setting.on("themes", this.handelThemeChange); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public componentWillUnmount() { | ||||
|         if (this.props.setting) { | ||||
|             this.props.setting.off("themes", this.handelThemeChange); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public render(): ReactNode { | ||||
| 
 | ||||
|         const setting = this.props.setting; | ||||
|         const classNameList: string[] = []; | ||||
| 
 | ||||
|         if (this.props.className) { | ||||
|             classNameList.push(this.props.className); | ||||
|         } | ||||
| 
 | ||||
|         const theme = setting ? setting.themes : Themes.dark; | ||||
|         classNameList.push(theme === Themes.light ? "light" : "dark"); | ||||
| 
 | ||||
|         if (this.props.fontLevel) { | ||||
|             classNameList.push(`font-${this.props.fontLevel}`); | ||||
|         } | ||||
|          | ||||
|         if (this.props.backgroundLevel) { | ||||
|             classNameList.push(`background-${this.props.backgroundLevel}`); | ||||
|         } | ||||
| 
 | ||||
|         const propsObj = {...this.props}; | ||||
|         delete propsObj.className; | ||||
|         delete propsObj.setting; | ||||
|         delete propsObj.backgroundLevel; | ||||
|         delete propsObj.fontLevel; | ||||
| 
 | ||||
|         return <div {...propsObj} className={`${classNameList.join(" ")}`}> | ||||
|             { this.props.children } | ||||
|         </div> | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export default Theme; | ||||
| export { Theme, FontLevel, BackgroundLevel }; | ||||
							
								
								
									
										65
									
								
								source/Context/Setting.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								source/Context/Setting.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | ||||
| import { createContext, Component, FunctionComponent } from "react"; | ||||
| import { Emitter } from "@Model/Emitter"; | ||||
| 
 | ||||
| /** | ||||
|  * 主题模式 | ||||
|  */ | ||||
| enum Themes { | ||||
|     light = 1, | ||||
|     dark = 2 | ||||
| } | ||||
| 
 | ||||
| type Language = "ZH_CN" | "EN_US"; | ||||
| 
 | ||||
| class Setting extends Emitter< | ||||
|     Setting & {change: keyof Setting} | ||||
| > { | ||||
| 
 | ||||
|     /** | ||||
|      * 主题 | ||||
|      */ | ||||
|     public themes: Themes = Themes.dark; | ||||
| 
 | ||||
|     /** | ||||
|      * 语言 | ||||
|      */ | ||||
|     public language: Language = "EN_US"; | ||||
| 
 | ||||
|     /** | ||||
|      * 设置参数 | ||||
|      */ | ||||
|     public setProps<P extends keyof Setting>(key: P, value: Setting[P]) { | ||||
|         this[key] = value as any; | ||||
|         this.emit("change", key); | ||||
|         this.emit(key as any, value as any); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| interface IMixinSettingProps { | ||||
|     setting?: Setting; | ||||
| } | ||||
| 
 | ||||
| const SettingContext = createContext<Setting>(new Setting()); | ||||
| 
 | ||||
| SettingContext.displayName = "Setting"; | ||||
| const SettingProvider = SettingContext.Provider; | ||||
| const SettingConsumer = SettingContext.Consumer; | ||||
| 
 | ||||
| type RenderComponent = (new (...p: any) => Component<any, any, any>) | FunctionComponent<any>; | ||||
| 
 | ||||
| /** | ||||
|  * 修饰器 | ||||
|  */ | ||||
| function useSetting<R extends RenderComponent>(components: R): R { | ||||
|     return ((props: any) => { | ||||
|         const C = components; | ||||
|         return <SettingConsumer> | ||||
|             {(setting: Setting) => <C {...props} setting={setting}></C>} | ||||
|         </SettingConsumer> | ||||
|     }) as any; | ||||
| } | ||||
| 
 | ||||
| export { | ||||
|     Themes, Setting, SettingContext, useSetting, Language, | ||||
|     IMixinSettingProps, SettingProvider, SettingConsumer | ||||
| }; | ||||
							
								
								
									
										53
									
								
								source/Context/Status.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								source/Context/Status.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| import { createContext, Component, FunctionComponent } from "react"; | ||||
| import { Emitter } from "@Model/Emitter"; | ||||
| import { Model } from "@Model/Model"; | ||||
| import { Archive } from "@Model/Archive"; | ||||
| import { AbstractRenderer } from "@Model/Renderer"; | ||||
| 
 | ||||
| class Status extends Emitter<{}> { | ||||
| 
 | ||||
|     /** | ||||
|      * 渲染器 | ||||
|      */ | ||||
|     public renderer: AbstractRenderer = undefined as any; | ||||
| 
 | ||||
|     /** | ||||
|      * 文件状态 | ||||
|      */ | ||||
|     public archive: Archive = new Archive(); | ||||
| 
 | ||||
|     /** | ||||
|      * 模型状态 | ||||
|      */ | ||||
|     public model: Model = new Model(); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| interface IMixinStatusProps { | ||||
|     status?: Status; | ||||
| } | ||||
| 
 | ||||
| const StatusContext = createContext<Status>(new Status()); | ||||
| 
 | ||||
| StatusContext.displayName = "Status"; | ||||
| const StatusProvider = StatusContext.Provider; | ||||
| const StatusConsumer = StatusContext.Consumer; | ||||
| 
 | ||||
| type RenderComponent = (new (...p: any) => Component<any, any, any>) | FunctionComponent<any>; | ||||
| 
 | ||||
| /** | ||||
|  * 修饰器 | ||||
|  */ | ||||
| function useStatus<R extends RenderComponent>(components: R): R { | ||||
|     return ((props: any) => { | ||||
|         const C = components; | ||||
|         return <StatusConsumer> | ||||
|             {(status: Status) => <C {...props} status={status}></C>} | ||||
|         </StatusConsumer> | ||||
|     }) as any; | ||||
| } | ||||
| 
 | ||||
| export { | ||||
|     Status, StatusContext, useStatus, | ||||
|     IMixinStatusProps, StatusProvider, StatusConsumer | ||||
| }; | ||||
| @ -5,7 +5,9 @@ import { GLContext } from "./GLContext"; | ||||
| import { Camera } from "./Camera"; | ||||
| import { Clock } from "@GLRender/Clock"; | ||||
| 
 | ||||
| interface IRendererOwnParams {} | ||||
| interface IRendererOwnParams { | ||||
|     canvas: HTMLCanvasElement; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 渲染器参数 | ||||
| @ -38,7 +40,7 @@ abstract class BasicRenderer< | ||||
|      */ | ||||
|     protected clock: Clock; | ||||
| 
 | ||||
|     public constructor(canvas: HTMLCanvasElement, param: Partial<M & IRendererParams> = {}) { | ||||
|     public constructor(param: Partial<M & IRendererParams> = {}) { | ||||
| 		super(); | ||||
| 
 | ||||
| 		// 初始化参数
 | ||||
| @ -50,7 +52,7 @@ abstract class BasicRenderer< | ||||
| 		} as M & IRendererParams; | ||||
| 		 | ||||
| 		// 实例化画布对象
 | ||||
| 		this.canvas = new GLCanvas(canvas, this.param); | ||||
| 		this.canvas = new GLCanvas(param.canvas, this.param); | ||||
| 
 | ||||
|         // 实例化摄像机
 | ||||
|         this.camera = new Camera(this.canvas); | ||||
| @ -154,7 +156,7 @@ abstract class BasicRenderer< | ||||
|     /** | ||||
|      * 初始化 | ||||
|      */ | ||||
|     abstract onLoad(): void; | ||||
|     abstract onLoad(): this; | ||||
| 
 | ||||
|     /** | ||||
|      * 渲染器执行 | ||||
|  | ||||
| @ -34,7 +34,7 @@ class ClassicRenderer extends BasicRenderer<{}, IClassicRendererParams> { | ||||
|      */ | ||||
|     private objectPool = new Map<ObjectID, DisplayObject>(); | ||||
| 
 | ||||
|     public onLoad(): void { | ||||
|     public onLoad(): this { | ||||
|          | ||||
|         // 自动调节分辨率
 | ||||
|         this.autoResize(); | ||||
| @ -69,6 +69,8 @@ class ClassicRenderer extends BasicRenderer<{}, IClassicRendererParams> { | ||||
|         // setInterval(() => {
 | ||||
|         //     this.basicGroup.upLoadData(new Array(100 * 3).fill(0).map(() => (Math.random() - .5) * 2));
 | ||||
|         // }, 500);
 | ||||
| 
 | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     loop(t: number): void { | ||||
|  | ||||
							
								
								
									
										5
									
								
								source/Localization/EN-US.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								source/Localization/EN-US.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| const EN_US = { | ||||
|     "EN_US": "English (US)", | ||||
|     "ZH_CN": "Chinese (Simplified)" | ||||
| } | ||||
| export default EN_US; | ||||
							
								
								
									
										5
									
								
								source/Localization/ZH-CN.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								source/Localization/ZH-CN.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| const ZH_CN = { | ||||
|     "EN_US": "英语 (美国)", | ||||
|     "ZH_CN": "中文 (简体)" | ||||
| } | ||||
| export default ZH_CN; | ||||
							
								
								
									
										42
									
								
								source/Model/Archive.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								source/Model/Archive.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| import { Emitter, EventType, EventMixin } from "./Emitter"; | ||||
| 
 | ||||
| interface IArchiveEvent { | ||||
|     save: Archive; | ||||
|     load: Archive; | ||||
| } | ||||
| 
 | ||||
| class Archive< | ||||
|     M extends any = any, | ||||
|     E extends Record<EventType, any> = {} | ||||
| > extends Emitter<E> { | ||||
| 
 | ||||
|     /** | ||||
|      * 是否为新文件 | ||||
|      */ | ||||
|     public isNewFile: boolean = true; | ||||
| 
 | ||||
|     /** | ||||
|      * 文件名 | ||||
|      */ | ||||
|     public fileName?: string; | ||||
| 
 | ||||
|     /** | ||||
|      * 文件数据 | ||||
|      */ | ||||
|     public fileData?: M; | ||||
| 
 | ||||
|     /** | ||||
|      * 保存文件 | ||||
|      * 模型转换为文件 | ||||
|      */ | ||||
|     public save() {}; | ||||
| 
 | ||||
|     /** | ||||
|      * 加载文件为模型 | ||||
|      * return Model | ||||
|      */ | ||||
|     public load() {}; | ||||
| } | ||||
| 
 | ||||
| export { Archive }; | ||||
| export default Archive; | ||||
| @ -21,10 +21,8 @@ class Laboratory extends Component { | ||||
|             throw new Error("Laboratory: 重复引用 canvas 节点"); | ||||
|         } | ||||
| 
 | ||||
|         const canvas = document.createElement("canvas"); | ||||
|         const renderer = new ClassicRenderer(canvas, { className: "canvas" }); | ||||
|         const renderer = new ClassicRenderer({ className: "canvas" }).onLoad(); | ||||
|         this.canvasContRef.current.appendChild(renderer.canvas.dom); | ||||
|         renderer.onLoad(); | ||||
| 
 | ||||
|         let model = new Model().bindRenderer(renderer); | ||||
|         let group = model.addGroup(); | ||||
|  | ||||
| @ -0,0 +1,6 @@ | ||||
| div.app-root { | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     position: absolute; | ||||
|     overflow: hidden; | ||||
| } | ||||
| @ -1,13 +1,70 @@ | ||||
| import { Component, ReactNode, createRef } from "react"; | ||||
| import { Component, ReactNode } from "react"; | ||||
| import { SettingProvider, Setting } from "@Context/Setting"; | ||||
| import { HeaderBar } from "@Component/HeaderBar/HeaderBar"; | ||||
| import { Theme, FontLevel, BackgroundLevel } from "@Component/Theme/Theme"; | ||||
| import { Localization } from "@Component/Localization/Localization"; | ||||
| import { Entry } from "../Entry/Entry"; | ||||
| import { StatusProvider, Status } from "@Context/Status"; | ||||
| import { ClassicRenderer } from "@GLRender/ClassicRenderer"; | ||||
| import "./SimulatorWeb.scss"; | ||||
| 
 | ||||
| class SimulatorWeb extends Component { | ||||
|      | ||||
|     private canvasContRef = createRef<HTMLDivElement>(); | ||||
|     /** | ||||
|      * 全局设置 | ||||
|      */ | ||||
|     private setting: Setting; | ||||
| 
 | ||||
|     /** | ||||
|      * 全局状态 | ||||
|      */ | ||||
|     private status: Status; | ||||
| 
 | ||||
|     public constructor(props: any) { | ||||
|         super(props); | ||||
| 
 | ||||
|         // TODO: 这里要读取设置
 | ||||
|         this.setting = new Setting(); | ||||
|         (window as any).setting = (this.setting as any); | ||||
| 
 | ||||
|         // TODO: 这里要读取存档
 | ||||
|         this.status = new Status(); | ||||
|         this.status.renderer = new ClassicRenderer({ className: "canvas" }).onLoad(); | ||||
|         this.status.model.bindRenderer(this.status.renderer); | ||||
| 
 | ||||
|         // 测试代码
 | ||||
|         if (true) { | ||||
|             let group = this.status.model.addGroup(); | ||||
|             let range = this.status.model.addRange(); | ||||
|             range.color = [.1, .5, .9]; | ||||
|             group.new(100); | ||||
|             group.color = [.8, .1, .6]; | ||||
|             group.individuals.forEach((individual) => { | ||||
|                 individual.position[0] = (Math.random() - .5) * 2; | ||||
|                 individual.position[1] = (Math.random() - .5) * 2; | ||||
|                 individual.position[2] = (Math.random() - .5) * 2; | ||||
|             }) | ||||
|             this.status.model.update(0); | ||||
|         } | ||||
| 
 | ||||
|         (window as any).s = this; | ||||
|     } | ||||
| 
 | ||||
|     public render(): ReactNode { | ||||
|         return <div>Web</div> | ||||
|         return <SettingProvider value={this.setting}> | ||||
|             <StatusProvider value={this.status}> | ||||
|                 {this.renderContent()} | ||||
|             </StatusProvider> | ||||
|         </SettingProvider> | ||||
|     } | ||||
| 
 | ||||
|     private renderContent(): ReactNode { | ||||
|         return <Theme  | ||||
|             className="app-root" | ||||
|             backgroundLevel={BackgroundLevel.Level5} | ||||
|         > | ||||
|             <HeaderBar height={45}/> | ||||
|         </Theme> | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| { | ||||
|     "compileOnSave": true, | ||||
|     "compilerOptions": { | ||||
|         "experimentalDecorators": true, | ||||
|         "resolveJsonModule": true, | ||||
|         "alwaysStrict": true, | ||||
|         "strict": true, | ||||
|         "sourceMap": true, | ||||
| @ -23,6 +25,12 @@ | ||||
|             ], | ||||
|             "@GLRender/*": [ | ||||
|                 "./source/GLRender/*" | ||||
|             ], | ||||
|             "@Context/*": [ | ||||
|                 "./source/Context/*" | ||||
|             ], | ||||
|             "@Component/*": [ | ||||
|                 "./source/Component/*" | ||||
|             ] | ||||
|         } | ||||
|     }, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user