[FEATURE] 初始化YasatInkCanvas并初步实现backgroundColor,正在实现稿纸格式。
This commit is contained in:
parent
ef93865a2a
commit
faf87ea0d4
@ -2,5 +2,12 @@
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="false" level="TEXT ATTRIBUTES" enabled_by_default="false" editorAttributes="TEXT_STYLE_SUGGESTION" />
|
||||
<inspection_tool class="com.haulmont.rcb.ArrayToJSXMapInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="com.haulmont.rcb.ConvertUnresolvedToStateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="com.haulmont.rcb.EmptyAttributeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="com.haulmont.rcb.EmptyRefInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="com.haulmont.rcb.ExhaustiveDepsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="com.haulmont.rcb.NonExistentPropUsageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="com.haulmont.rcb.PaletteExtLocalInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
@ -5,4 +5,3 @@
|
||||
<h1 style="text-align:center;">dot-yasat</h1>
|
||||
|
||||
<div style="text-align:center; margin-top:1rem">基于Electron与PyQt开发的PPT批注工具</div>
|
||||
<div style="text-align:center; margin-top:1rem">此项目不再积极维护</div>
|
||||
|
@ -2,6 +2,7 @@ import { resolve } from 'path'
|
||||
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import UnoCSS from 'unocss/vite'
|
||||
import million from 'million/compiler'
|
||||
|
||||
export default defineConfig({
|
||||
main: {
|
||||
@ -17,5 +18,8 @@ export default defineConfig({
|
||||
}
|
||||
},
|
||||
plugins: [react(),UnoCSS()],
|
||||
server: {
|
||||
host: "0.0.0.0"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -26,9 +26,13 @@
|
||||
"@radix-ui/themes": "^2.0.1",
|
||||
"@studio-freight/react-lenis": "^0.0.38",
|
||||
"@unocss/reset": "^0.57.5",
|
||||
"ahooks": "^3.7.10",
|
||||
"electron-updater": "^6.1.7",
|
||||
"express": "^4.18.2",
|
||||
"fabric": "^5.3.0",
|
||||
"million": "^3.0.3",
|
||||
"pako": "^2.1.0",
|
||||
"perfect-freehand": "^1.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-aria-components": "^1.0.1",
|
||||
"react-dom": "^18.2.0",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@ function createWindow() {
|
||||
hasShadow: false,
|
||||
movable: false,
|
||||
resizable: false,
|
||||
focusable: false,
|
||||
focusable: process.platform === 'darwin', // 因为macOS只会在可focus的情况下显示自定义cursor
|
||||
backgroundColor: "#00000000",
|
||||
...(process.platform === 'darwin' ? { acceptFirstMouse: true } : {}),
|
||||
...(process.platform === 'darwin' ? { visualEffectState: "inactive" } : {}),
|
||||
|
@ -1,17 +1,40 @@
|
||||
import YasatMainWindow from './YasatMainWindow.jsx'
|
||||
import DotYasatLogo from "./assets/dot-yasat-logo.png"
|
||||
import YasatInkCanvas from './YasatInkCanvas'
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
function App() {
|
||||
const inkCanvasRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
// setTimeout(()=>{
|
||||
// inkCanvasRef.current["_"]({
|
||||
// action: "SET_BACKGROUND",
|
||||
// backgroundColor: "rgba(0,0,0,1)"
|
||||
// })
|
||||
// },2000);
|
||||
inkCanvasRef.current["_"]({
|
||||
action: "SET_BACKGROUND_COLOR",
|
||||
value: "blackboard-green"
|
||||
})
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{/*<div className="w-screen h-screen bg-#274C43 overflow-hidden flex items-end justify-center relative">*/}
|
||||
<div className="w-screen h-screen bg-transparent overflow-hidden flex items-end justify-center relative">
|
||||
<YasatMainWindow/>
|
||||
<div className="absolute z-0 inset-0 flex flex-col justify-center items-center pointer-events-none">
|
||||
<img src={DotYasatLogo} className="opacity-20 h-48 invert"/>
|
||||
<div className="text-3xl font-bold opacity-20 text-zinc-200">流利书写,流畅教学</div>
|
||||
<div className="text-lg font-medium mt-4 opacity-15 text-zinc-200 flex items-center">
|
||||
<YasatInkCanvas
|
||||
wrapperClassName="absolute z-2 top-0 left-0 w-screen h-screen"
|
||||
canvasClassName=""
|
||||
width="full" height="full"
|
||||
ref={inkCanvasRef}
|
||||
/>
|
||||
<div className="absolute z-1 pointer-events-none inset-0 flex flex-col justify-center items-center pointer-events-none">
|
||||
<img src={DotYasatLogo} className="opacity-20 h-48"/>
|
||||
<div className="text-3xl font-bold opacity-20 text-zinc-800">流利书写,流畅教学</div>
|
||||
<div className="text-lg font-medium mt-4 opacity-15 text-zinc-800 flex items-center">
|
||||
<div>巴南中学高2027级15班刘晨曦用</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" fill="none" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
@ -19,7 +42,7 @@ function App() {
|
||||
</svg>
|
||||
<div>开发</div>
|
||||
</div>
|
||||
<div className="text-lg mt-12 opacity-15 text-zinc-200 flex items-center space-x-2">
|
||||
<div className="text-lg mt-12 opacity-15 text-zinc-800 flex items-center space-x-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5.5 w-5.5" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" fill="none" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
||||
@ -30,7 +53,6 @@ function App() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
149
electron/dot-yasat/src/renderer/src/YasatInkCanvas.jsx
Normal file
149
electron/dot-yasat/src/renderer/src/YasatInkCanvas.jsx
Normal file
@ -0,0 +1,149 @@
|
||||
import { forwardRef, useEffect, useImperativeHandle, useMemo, useReducer, useRef } from 'react'
|
||||
import { fabric } from "fabric"
|
||||
import { useSize } from 'ahooks'
|
||||
|
||||
import resources_tianzige from "./resources/manuscript/tianZiGe.png"
|
||||
import resources_mizige from "./resources/manuscript/miZiGe.png"
|
||||
import resources_english from "./resources/manuscript/english.png"
|
||||
|
||||
/**
|
||||
* @param state
|
||||
* @param {object} action
|
||||
* */
|
||||
function _reducer(state, action) {
|
||||
switch (action.action) {
|
||||
case "SET_BACKGROUND_COLOR": {
|
||||
if ((["transparent","blackboard-green","black","gray","zinc","white","pure-white"]).includes(action.value)===true) {
|
||||
return { ...state, backgroundColor:action.value };
|
||||
} else {
|
||||
console.error(`"SET_BACKGROUND_COLOR" 仅接受 "transparent" | "blackboard-green" | "black" | "gray" | "zinc" | "white" | "pure-white",其他的非法值不被允许!没有任何值被更改!`);
|
||||
return { ...state };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default forwardRef(
|
||||
/**
|
||||
* @param {{
|
||||
* wrapperClassName :string,
|
||||
* canvasClassName :string,
|
||||
* width :string | number,
|
||||
* height :string | number,
|
||||
* backgroundColor: "transparent" | "blackboard-green" | "black" | "gray" | "zinc" | "white" | "pure-white",
|
||||
* }} props
|
||||
* @param ref
|
||||
* */
|
||||
function YasatInkCanvas(props, ref) {
|
||||
const canvasRef = useRef(null);
|
||||
const fabricRef = useRef(null);
|
||||
|
||||
const size = useSize(document.querySelector("html"));
|
||||
|
||||
const [state, dispatch] = useReducer(_reducer, {
|
||||
/*
|
||||
* 此处接受 "transparent" | "blackboard-green" | "black" | "gray" | "zinc" | "white" | "pure-white"
|
||||
* 使用 "SET_BACKGROUND_COLOR" 来修改背景颜色或者通过给组件传入backgroundColor props来设置背景颜色
|
||||
* 注意:传入backgroundColor props后将会让此值成为"component-props-driven"模式,无法使用 "SET_BACKGROUND_COLOR" 来修改背景颜色!
|
||||
* 如果需要设置自定义背景格式,请使用 "SET_CUSTOM_BACKGROUND"
|
||||
* */
|
||||
backgroundColor: "transparent",
|
||||
// 启用稿纸格式将会强制让画布变为透明背景,背景将会在画布下一层的div中生效。
|
||||
enableManuscriptFormat: true,
|
||||
/*
|
||||
* 设置背景稿纸格式
|
||||
* 支持 "chinese-tian" | "chinese-mi" | "english" | "music-fiveline"
|
||||
* */
|
||||
manuscriptType: "english",
|
||||
});
|
||||
|
||||
const actualBackgroundColor = useMemo(() => (
|
||||
(props.backgroundColor??state.backgroundColor)==="transparent"?"rgba(0,0,0,0)":
|
||||
(props.backgroundColor??state.backgroundColor)==="blackboard-green"?"rgba(22,55,36,1)":
|
||||
(props.backgroundColor??state.backgroundColor).backgroundColor==="black"?"rgba(0,0,0,1)":
|
||||
(props.backgroundColor??state.backgroundColor).backgroundColor==="gray"?"#111827":
|
||||
(props.backgroundColor??state.backgroundColor).backgroundColor==="zinc"?"#18181b":
|
||||
(props.backgroundColor??state.backgroundColor).backgroundColor==="white"?"#f4f4f5":
|
||||
(props.backgroundColor??state.backgroundColor).backgroundColor==="pure-white"?"rgba(255,255,255,1)":
|
||||
// fallback value
|
||||
"rgba(0,0,0,0)"), [props.backgroundColor,state.backgroundColor]);
|
||||
|
||||
// 手动更新宽高
|
||||
useEffect(() => {
|
||||
fabricRef.current?.setDimensions({
|
||||
width: props.width === "full" ? size.width : props.width,
|
||||
height: props.height === "full" ? size.height : props.height,
|
||||
})
|
||||
}, [size.width, size.height, props.height, props.width]);
|
||||
|
||||
// 初始化fabric.js
|
||||
useEffect(() => {
|
||||
console.log("%cYasatInkCanvas v0.1.0","font-size:18pt;font-weight:bold;")
|
||||
|
||||
fabricRef.current = new fabric.Canvas(canvasRef.current);
|
||||
|
||||
// 初始化画布宽高
|
||||
fabricRef.current?.setDimensions({
|
||||
width: props.width === "full" ? size.width : props.width,
|
||||
height: props.height === "full" ? size.height : props.height,
|
||||
})
|
||||
|
||||
// 设置背景颜色
|
||||
fabricRef.current?.setBackgroundColor("rgba(0,0,0,0)")
|
||||
|
||||
// 销毁fabric.js实例
|
||||
return () => {
|
||||
fabricRef.current.dispose();
|
||||
fabricRef.current = undefined;
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 更新backgroundColor的Effect
|
||||
useEffect(() => {
|
||||
if (state.enableManuscriptFormat===true) {
|
||||
fabricRef.current?.setBackgroundColor("rgba(0,0,0,0)",fabricRef.current?.renderAll.bind(fabricRef.current))
|
||||
} else {
|
||||
fabricRef.current?.setBackgroundColor(actualBackgroundColor, fabricRef.current?.renderAll.bind(fabricRef.current));
|
||||
}
|
||||
}, [state.backgroundColor,props.backgroundColor]);
|
||||
|
||||
// 暴露 _ 到ref
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => {
|
||||
return {
|
||||
_: (action)=>{
|
||||
dispatch({
|
||||
fabric: fabricRef.current,
|
||||
...action
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
[state],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={"relative "+props.wrapperClassName}>
|
||||
{state.enableManuscriptFormat?(
|
||||
<div className="manuscript-layer absolute top-0 left-0 w-full h-full -z-1 flex items-center justify-center" style={{backgroundColor:actualBackgroundColor}}>
|
||||
{state.manuscriptType==="chinese-tian"||state.manuscriptType==="chinese-mi"||state.manuscriptType==="english"?(
|
||||
<div className={"grid grid-cols-5 w-fit h-fit "+(state.manuscriptType!=="english"?"border-l-2 border-r-2 border-t-1 border-b-1 border-white":"")}>
|
||||
{(new Array(5).fill(null)).map((_,__)=>
|
||||
<img alt="" key={__} src={state.manuscriptType==="chinese-mi"?resources_mizige:state.manuscriptType==="chinese-tian"?resources_tianzige:resources_english} className="h-15vw object-contain" />
|
||||
)}
|
||||
<div className={"col-span-5 -mt-1 "+(state.manuscriptType!=="english"?"ring-2 ring-inset ring-white h-4vw":"h-10vw")}></div>
|
||||
{(new Array(5).fill(null)).map((_,__)=>
|
||||
<img alt="" key={__} src={state.manuscriptType==="chinese-mi"?resources_mizige:state.manuscriptType==="chinese-tian"?resources_tianzige:resources_english} className="h-15vw object-contain" />
|
||||
)}
|
||||
</div>
|
||||
):void 0}
|
||||
</div>
|
||||
):void 0}
|
||||
<canvas ref={canvasRef} className={props.canvasClassName} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
)
|
@ -1301,6 +1301,7 @@ export default function YasatMainWindow(props) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex justify-center fixed z-5 bottom-0 left-0 w-screen">
|
||||
<div className="flex flex-col h-fit w-fit space-y-1 relative">
|
||||
|
||||
{/*penMenu*/}
|
||||
@ -3244,7 +3245,7 @@ export default function YasatMainWindow(props) {
|
||||
</div>
|
||||
|
||||
{/*LeftToolBar*/}
|
||||
<div className="fixed bottom-0 left-0 w-fit h-fit">
|
||||
<div className="z-10 fixed bottom-0 left-0 w-fit h-fit">
|
||||
<div className="flex flex-col h-fit w-fit space-y-1 relative">
|
||||
{/*mainMenu*/}
|
||||
<div className="relative flex h-0 w-full justify-start">
|
||||
@ -3601,7 +3602,7 @@ export default function YasatMainWindow(props) {
|
||||
</div>
|
||||
|
||||
{/*RightToolBar*/}
|
||||
<div className="fixed bottom-0 right-0 w-fit h-fit">
|
||||
<div className="z-10 fixed bottom-0 right-0 w-fit h-fit">
|
||||
<div className="flex flex-col h-fit w-fit space-y-1 relative">
|
||||
<div className="flex h-fit w-fit items-center justify-center space-x-1">
|
||||
<div className="rounded-lg transition-all bg-zinc-50 border border-zinc-300 shadow-md flex w-fit items-center justify-center select-none overflow-clip">
|
||||
@ -3687,6 +3688,7 @@ export default function YasatMainWindow(props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Toaster position="bottom-center" containerClassName="mb-18" />
|
||||
<YasatSettingsWindow ref={YasatSettingsWindowRef}/>
|
||||
|
@ -101,7 +101,7 @@ export default forwardRef(function YasatSettingsWindow(props, ref){
|
||||
</div>
|
||||
</div>
|
||||
<ReactLenis options={{
|
||||
duraton : 0.05,
|
||||
duration : 0.2,
|
||||
}} className="select-none pr-6 w-full grow overflow-y-scroll scrollbar scrollbar-thumb-color-zinc-800/50 scrollbar-w-1 scrollbar-rounded overflow-x-clip flex flex-col">
|
||||
<div className="h-fit w-full">
|
||||
<div className="text-center text-sm font-medium text-zinc-800 mb-2 select-none">设置将自动保存,若无特别说明则选项修改后立刻生效</div>
|
||||
|
@ -6,7 +6,7 @@ import './main.css'
|
||||
import 'virtual:uno.css'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<React.StrictMode>
|
||||
// <React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
// </React.StrictMode>,
|
||||
)
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
Reference in New Issue
Block a user