Commit e3c9c5df authored by fanxuehui's avatar fanxuehui

feat: store

parent e4ce8b08
module.exports = {
parser: '@typescript-eslint/parser',
extends: ['plugin:@typescript-eslint/recommended'],
extends: [
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
'prettier/@typescript-eslint',
'plugin:prettier/recommended',
],
plugins: ['@typescript-eslint'],
env: {
browser: true,
node: true,
},
settings: {
react: {
pragma: 'React',
version: 'detect',
},
},
parserOptions: {
ecmaVersion: 2019,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
rules: {
'@typescript-eslint/interface-name-prefix': ['never'],
......
import React from 'react';
import { toJS } from 'mobx';
import withLayer from '@hoc/layer';
import styles from './index.less';
/*
* todo
* 和数据流解耦
*/
function Canvas({ stageStore }) {
return (
<div>
<div className={styles.extend_canvas}>
<p>extended Canvas</p>
{stageStore.data.widgetList.map((wrappedWidget) => (
<wrappedWidget.widget.layer
key={wrappedWidget.id}
setFocus={() => stageStore.setFocus(wrappedWidget.id)}
style={toJS(wrappedWidget.style)}
></wrappedWidget.widget.layer>
))}
{stageStore.targetPage.widgetList.map((wrappedWidget) => {
const WrappedLayer = withLayer(wrappedWidget);
return <WrappedLayer key={wrappedWidget.id}></WrappedLayer>;
})}
</div>
);
}
......
.extend_canvas {
position: relative;
width: 375px;
margin: auto;
}
......@@ -10,7 +10,10 @@ const Editor: ComponentType<WidgetEditorProps> = function Editor({
<p>num: {target.id}</p>
<button
onClick={() => {
changeTargetProps({ backgroundColor: target.style.backgroundColor==='red'?'blue':'red' });
changeTargetProps({
'style.backgroundColor':
target.style.backgroundColor === 'red' ? 'blue' : 'red',
});
}}
>
change color
......
......@@ -6,4 +6,5 @@ export default {
data: {
bg: { type: WidgetDataTypes.Text, value: '' },
},
style: { width: '100px', height: '100px' },
};
......@@ -33,6 +33,7 @@
"author": "Dec-F",
"license": "MIT",
"devDependencies": {
"@types/lodash-es": "^4.17.3",
"@types/react": "^16.9.35",
"@types/react-dnd": "^3.0.2",
"@types/react-dom": "^16.9.8",
......@@ -44,6 +45,8 @@
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.5.3",
"eslint": "^5.16.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"html-loader": "^1.1.0",
"html-webpack-plugin": "^4.3.0",
"less-loader": "^6.1.0",
......@@ -51,6 +54,7 @@
"postcss-loader": "^3.0.0",
"postcss-pxtorem": "^5.1.1",
"precss": "^4.0.0",
"prettier": "^2.0.5",
"standard-version": "^7.0.1",
"style-loader": "^1.2.1",
"ts-loader": "^7.0.4",
......@@ -63,6 +67,7 @@
},
"dependencies": {
"antd": "^4.2.4",
"lodash-es": "^4.17.15",
"mobx": "^5.15.4",
"mobx-react": "^6.2.2",
"react": "^16.13.1",
......
......@@ -11,8 +11,28 @@ function Stage() {
const { scopeStore, stageStore } = useStore();
const { canvas } = scopeStore;
const handleClick = () => {};
function handleMouseMove(e) {
e.preventDefault();
typeof window.__widgetMouseMove__ === 'function' &&
window.__widgetMouseMove__(e.clientX, e.clientY);
typeof window.__widgetResizerMouseMove__ === 'function' &&
window.__widgetResizerMouseMove__(e);
}
function handleMouseUp(e) {
if (typeof window.__widgetMouseUp__ === 'function') {
window.__widgetMouseUp__(e.clientX, e.clientY);
} else if (typeof window.__widgetResizerMouseMUp__ === 'function') {
window.__widgetResizerMouseMUp__(e);
} else {
}
}
return (
<div onClick={handleClick} className={styles.stage}>
<div
onClick={handleClick}
className={styles.stage}
onMouseMoveCapture={handleMouseMove}
onMouseUp={handleMouseUp}
>
<CardHost></CardHost>
<CanvasHost></CanvasHost>
<ExtendedConcrols></ExtendedConcrols>
......
......@@ -7,10 +7,10 @@ import { CanvasWrapperUniqueId } from '@config';
import { IWidget } from '@shared/interfaces';
function withCardItem(
Widget: IWidget,
type,
type: string,
defaultAttrs = { style: { width: '100px' } }
) {
function wrapped() {
function wrapper() {
const { scopeStore, stageStore } = useStore();
const [collectedProps, drag] = useDrag({
item: { id: '', type },
......@@ -85,6 +85,7 @@ function withCardItem(
id,
...defaultAttrs,
...attrs,
...Widget.meta,
widget: Widget,
});
}
......@@ -98,6 +99,7 @@ function withCardItem(
id: uuidGen(),
...defaultAttrs,
...attrs,
...Widget.meta,
widget: Widget,
});
}}
......@@ -106,7 +108,7 @@ function withCardItem(
);
}
return wrapped;
return wrapper;
}
export default withCardItem;
@squareWidth: 8px;
@handlerWidth: 16px;
@rotateOffsetY: 50px;
@borderColor: rgb(255, 82, 82);
.widget_layer_wrapper {
box-sizing: border-box;
position: absolute;
user-select: none;
cursor: normal;
// Resizer Styles
.resizerTop,
.resizerBottom,
.resizerLeft,
.resizerRight {
position: absolute;
div {
position: absolute;
border: 1px solid @borderColor;
width: @squareWidth;
height: @squareWidth;
user-select: none;
background-color: #fff;
z-index: 2;
}
[class*='handler'] {
border: none;
width: @handlerWidth;
height: @handlerWidth;
opacity: 0;
z-index: 2;
user-select: none;
}
}
.resizerTop {
border-top: 1px solid @borderColor;
top: 0;
left: 0;
right: 0;
z-index: 3;
.lt {
left: -@squareWidth / 2;
top: -@squareWidth / 2;
}
.rt {
right: -@squareWidth / 2;
top: -@squareWidth / 2;
}
.ct {
left: calc(-@squareWidth / 2 + 50%);
top: -@squareWidth / 2;
}
.lt-handler {
left: -@handlerWidth / 2;
top: -@handlerWidth / 2;
cursor: nw-resize;
}
.rt-handler {
right: -@handlerWidth / 2;
top: -@handlerWidth / 2;
cursor: ne-resize;
}
.ct-handler {
left: calc(-@handlerWidth / 2 + 50%);
top: -@handlerWidth / 2;
cursor: n-resize;
}
.ro {
left: calc(-@squareWidth / 2 + 50%);
top: calc(-@squareWidth / 2 - @rotateOffsetY);
}
.ro-handler {
left: calc(-@handlerWidth / 2 + 50%);
top: calc(-@handlerWidth / 2 - @rotateOffsetY);
cursor: move;
}
}
.resizerBottom {
border-bottom: 1px solid @borderColor;
bottom: 0;
left: 0;
right: 0;
z-index: 3;
.rb {
right: -@squareWidth / 2;
bottom: -@squareWidth / 2;
}
.lb {
left: -@squareWidth / 2;
bottom: -@squareWidth / 2;
}
.cb {
left: calc(-@squareWidth / 2 + 50%);
bottom: -@squareWidth / 2;
}
.rb-handler {
right: -@handlerWidth / 2;
bottom: -@handlerWidth / 2;
cursor: se-resize;
}
.lb-handler {
left: -@handlerWidth / 2;
bottom: -@handlerWidth / 2;
cursor: sw-resize;
}
.cb-handler {
left: calc(-@handlerWidth / 2 + 50%);
bottom: -@handlerWidth / 2;
cursor: s-resize;
}
}
.resizerLeft {
border-left: 1px solid @borderColor;
top: 0;
left: 0;
bottom: 0;
z-index: 2;
.lm {
left: -@squareWidth / 2 - 1px;
top: calc(-@squareWidth / 2 + 50%);
}
.lm-handler {
left: -@handlerWidth / 2;
top: calc(-@handlerWidth / 2 + 50%);
cursor: w-resize;
}
}
.resizerRight {
border-right: 1px solid @borderColor;
top: 0;
bottom: 0;
right: 0;
z-index: 2;
.rm {
right: -@squareWidth / 2 - 1px;
top: calc(-@squareWidth / 2 + 50%);
}
.rm-handler {
right: -@handlerWidth / 2;
top: calc(-@handlerWidth / 2 + 50%);
cursor: e-resize;
}
}
// Indicator Styles
.indicatorV,
.indicatorH {
position: absolute;
z-index: 200;
}
.indicatorH {
top: 50%;
left: 0;
right: 0;
}
.indicatorV {
left: 50%;
top: 0;
bottom: 0;
}
}
import React, { useRef } from 'react';
import { getNumber } from '@utils/helper';
import { useStore } from '@hooks/use-store';
import { CanvasWrapperUniqueId } from '@config';
import { IWidget } from '@shared/interfaces';
import { toJS } from 'mobx';
import Resizer from './resizer';
import { observer } from 'mobx-react';
import styles from './index.less';
function withLayer(wrappedWidget) {
function Wrapper() {
const { scopeStore, stageStore } = useStore();
const wrapperRef = useRef<HTMLDivElement>();
const handleReszie = ({ width, height, left, top, deg }) => {
const widgetDom = document.querySelector<HTMLDivElement>(
`[wid="${wrappedWidget.id}"`
);
wrapperRef.current.style.left = left + 'px';
wrapperRef.current.style.top = top + 'px';
wrapperRef.current.style.width = width + 'px';
wrapperRef.current.style.height = height + 'px';
wrapperRef.current.style.transform = `rotate(${deg}deg)`;
};
const hanldeReszieComplete = ({ width, height, left, top, deg }) => {
const dpr = 1;
stageStore.changeTargetProps({
'style.width': width * dpr + 'px',
'style.height': height * dpr + 'px',
'style.left': left * dpr + 'px',
'style.top': top * dpr + 'px',
'style.transform': `rotate(${deg}deg)`,
});
};
return (
<div
className={styles.widget_layer_wrapper}
id={wrappedWidget.id}
ref={wrapperRef}
>
{stageStore.targetWidgetId === wrappedWidget.id ? (
<Resizer
onReszie={handleReszie}
onReszieComplete={hanldeReszieComplete}
targetStyle={wrappedWidget.style}
></Resizer>
) : (
''
)}
<wrappedWidget.widget.layer
setFocus={() => stageStore.chooseWidget(wrappedWidget.id)}
{...toJS(wrappedWidget)}
></wrappedWidget.widget.layer>
</div>
);
}
return observer(Wrapper);
}
export default withLayer;
import React, { useCallback, useState, useEffect, CSSProperties } from 'react';
import { useSetState } from 'react-use';
import { getNumber, getDeg } from '@utils/helper';
import { CanvasWrapperUniqueId } from '@config';
import styles from './index.less';
type IState = {
mouseInitPos: {
x: number;
y: number;
};
type: string;
initTarget: CSSProperties;
};
function Resizer(props) {
const [state, setState] = useSetState<IState>({
mouseInitPos: {
x: NaN,
y: NaN,
},
type: '',
initTarget: {},
});
const calc = useCallback(
(type, e) => {
if (type === 'lt') {
const offsetX = e.clientX - state.mouseInitPos.x;
const offsetY = e.clientY - state.mouseInitPos.y;
const width = getNumber(state.initTarget.width) + -offsetX;
const height = getNumber(state.initTarget.height) + -offsetY;
const left = getNumber(state.initTarget.left) + offsetX;
const top = getNumber(state.initTarget.top) + offsetY;
const deg = getNumber(state.initTarget.transform);
return {
width,
height,
left,
top,
deg,
};
} else if (type === 'ro') {
const { left, top, width, height } = state.initTarget;
const sceneInnerRect = document
.getElementById(CanvasWrapperUniqueId)
.getBoundingClientRect();
const deg = getDeg(
sceneInnerRect.left + getNumber(left) + getNumber(width) / 2,
sceneInnerRect.top + getNumber(top) + getNumber(height) / 2,
e.clientX,
e.clientY
);
return {
left: getNumber(left),
top: getNumber(top),
width: getNumber(width),
height: getNumber(height),
deg,
};
} else if (type === 'ct') {
const { left, top, width, height, transform } = state.initTarget;
const offsetY = e.clientY - state.mouseInitPos.y;
return {
width: getNumber(width),
height: getNumber(height) + -offsetY,
left: getNumber(left),
top: getNumber(top) + offsetY,
deg: getNumber(transform),
};
} else if (type === 'cb') {
const { left, top, width, height, transform } = state.initTarget;
const offsetY = e.clientY - state.mouseInitPos.y;
return {
width: getNumber(width),
height: getNumber(height) + offsetY,
left: getNumber(left),
top: getNumber(top),
deg: getNumber(transform),
};
} else if (type === 'lm') {
const { left, top, width, height, transform } = state.initTarget;
const offsetX = e.clientX - state.mouseInitPos.x;
return {
width: getNumber(width) + -offsetX,
height: getNumber(height),
left: getNumber(left) + offsetX,
top: getNumber(top),
deg: getNumber(transform),
};
} else if (type === 'rm') {
const { left, top, width, height, transform } = state.initTarget;
const offsetX = e.clientX - state.mouseInitPos.x;
return {
width: getNumber(width) + offsetX,
height: getNumber(height),
left: getNumber(left),
top: getNumber(top),
deg: getNumber(transform),
};
} else if (type === 'rt') {
const offsetX = e.clientX - state.mouseInitPos.x;
const offsetY = e.clientY - state.mouseInitPos.y;
const width = getNumber(state.initTarget.width) + offsetX;
const height = getNumber(state.initTarget.height) + -offsetY;
const left = getNumber(state.initTarget.left);
const top = getNumber(state.initTarget.top) + offsetY;
const deg = getNumber(state.initTarget.transform);
return {
width,
height,
left,
top,
deg,
};
} else if (type === 'rb') {
const offsetX = e.clientX - state.mouseInitPos.x;
const offsetY = e.clientY - state.mouseInitPos.y;
const width = getNumber(state.initTarget.width) + offsetX;
const height = getNumber(state.initTarget.height) + offsetY;
const left = getNumber(state.initTarget.left);
const top = getNumber(state.initTarget.top);
const deg = getNumber(state.initTarget.transform);
return {
width,
height,
left,
top,
deg,
};
} else if (type === 'lb') {
const offsetX = e.clientX - state.mouseInitPos.x;
const offsetY = e.clientY - state.mouseInitPos.y;
const width = getNumber(state.initTarget.width) + -offsetX;
const height = getNumber(state.initTarget.height) + offsetY;
const left = getNumber(state.initTarget.left) + offsetX;
const top = getNumber(state.initTarget.top);
const deg = getNumber(state.initTarget.transform);
return {
width,
height,
left,
top,
deg,
};
}
},
[state]
);
const handleMouseDown = (type, e) => {
e.persist();
e.stopPropagation();
setState({
mouseInitPos: {
x: e.clientX,
y: e.clientY,
},
type,
initTarget: { ...props.targetStyle },
});
};
const __handleMouseMove__ = useCallback(
(e) => {
e.persist();
e.stopPropagation();
const result = calc(state.type, e);
console.log(result, state.type, e);
props.onReszie(result);
},
[state]
);
const __handleMouseUp__ = useCallback(
(e) => {
e.stopPropagation();
const result = calc(state.type, e);
props.onReszieComplete(result);
setState({
initTarget: result,
type: '',
});
},
[state]
);
useEffect(() => {
if (state.type) {
window.__widgetResizerMouseMove__ = __handleMouseMove__;
window.__widgetResizerMouseMUp__ = __handleMouseUp__;
} else {
window.__widgetResizerMouseMove__ = null;
window.__widgetResizerMouseMUp__ = null;
}
}, [__handleMouseMove__, __handleMouseUp__, state]);
let { options } = props;
options || (options = {});
const { lt, rt, ct, ro, rm, rb, lb, cb, lm } = options;
return (
<React.Fragment>
<div className={styles['resizerTop']}>
<div className={styles['lt']} {...generateProps(lt)} />
<div className={styles['rt']} {...generateProps(rt)} />
<div className={styles['ct']} {...generateProps(ct)} />
<div className={styles['ro']} {...generateProps(ro)} />
<div
className={styles['lt-handler']}
{...generateProps(lt)}
onMouseDown={(e) =>
controlBehavior(e, lt) && handleMouseDown('lt', e)
}
/>
<div
className={styles['rt-handler']}
{...generateProps(rt)}
onMouseDown={(e) =>
controlBehavior(e, rt) && handleMouseDown('rt', e)
}
/>
<div
className={styles['ct-handler']}
{...generateProps(ct)}
onMouseDown={(e) =>
controlBehavior(e, ct) && handleMouseDown('ct', e)
}
/>
<div
className={styles['ro-handler']}
{...generateProps(ro)}
onMouseDown={(e) =>
controlBehavior(e, ro) && handleMouseDown('ro', e)
}
/>
</div>
<div className={styles['resizerRight']}>
<div className={styles['rm']} {...generateProps(rm)} />
<div
className={styles['rm-handler']}
{...generateProps(rm)}
onMouseDown={(e) =>
controlBehavior(e, rm) && handleMouseDown('rm', e)
}
/>
</div>
<div className={styles['resizerBottom']}>
<div className={styles['rb']} {...generateProps(rb)} />
<div className={styles['lb']} {...generateProps(lb)} />
<div className={styles['cb']} {...generateProps(cb)} />
<div
className={styles['rb-handler']}
{...generateProps(rb)}
onMouseDown={(e) =>
controlBehavior(e, rb) && handleMouseDown('rb', e)
}
/>
<div
className={styles['lb-handler']}
{...generateProps(lb)}
onMouseDown={(e) =>
controlBehavior(e, lb) && handleMouseDown('lb', e)
}
/>
<div
className={styles['cb-handler']}
{...generateProps(cb)}
onMouseDown={(e) =>
controlBehavior(e, cb) && handleMouseDown('cb', e)
}
/>
</div>
<div className={styles['resizerLeft']}>
<div className={styles['lm']} {...generateProps(lm)} />
<div
className={styles['lm-handler']}
{...generateProps(lm)}
onMouseDown={(e) =>
controlBehavior(e, lm) && handleMouseDown('lm', e)
}
/>
</div>
</React.Fragment>
);
}
export default Resizer;
// visible disabled hidden
function generateProps(type = 'visible') {
if (type === 'hidden') {
return {
style: {
display: 'none',
},
};
} else if (type === 'disabled') {
return {
style: {
borderColor: '#999',
cursor: 'not-allowed',
},
};
} else {
return {};
}
}
// visible disabled hidden
function controlBehavior(e, type = 'visible') {
if (type === 'disabled' || type === 'hidden') {
return e.stopPropagation();
} else {
return true;
}
}
......@@ -4,3 +4,10 @@ declare module '*.less' {
const classes: { [key: string]: string };
export default classes;
}
interface Window {
__widgetResizerMouseMUp__: function;
__widgetResizerMouseMove__: function;
__widgetMouseUp__: function;
__widgetMouseMove__: function;
}
......@@ -36,6 +36,7 @@ export interface IWidget {
}
export interface IWidgetAttrs {
id: string;
name?: string;
style: CSSProperties;
actionAttrs?: {
actionHide: IAction;
......@@ -75,9 +76,12 @@ export interface IEvent {
des: string;
pub?: string;
}
export interface ChangedObj {
[key: string]: any;
}
export interface WidgetEditorProps {
target: IWrappedWidget;
changeTargetProps: (style: CSSProperties) => void;
changeTargetProps: (obj: ChangedObj) => void;
}
interface WidgetIconProps {
addSelf: (attrs: IWidgetAttrs) => void;
......@@ -88,6 +92,8 @@ interface WidgetLayerProps {
// 产出JSON格式
export interface IPage {
id: string;
name: string;
attr: IPageAttr;
widgetList: IWrappedWidget[];
}
......@@ -95,4 +101,8 @@ export interface IPageAttr {
style: CSSProperties;
name: string;
id: string;
layout: IPageLayoutTypes;
}
export enum IPageLayoutTypes {
Absolute = 'ABSOLUTE',
}
// 舞台数据
import { observable, action, computed } from 'mobx';
import { IPage, IWidget, IWrappedWidget } from '../shared/interfaces';
import {
IPage,
IWidget,
IWrappedWidget,
IPageLayoutTypes,
ChangedObj,
} from '../shared/interfaces';
import { CSSProperties } from 'react';
import { set, cloneDeep } from 'lodash-es';
import { pageGen, getNumber, mutateValueByPath } from '@utils/helper';
import { uuidGen } from '@utils/uuid';
export class StageStore {
@observable
data: IPage = {
attr: {
style: { width: 100 },
id: '',
name: '',
},
widgetList: [],
};
data: IPage[] = [pageGen()];
// 当前编辑的页面
@observable
targetPageId: string = '';
// 当前编辑的组件
@observable
targetWidgetId: string = '';
@computed
get targetPage() {
return (
this.data.find((page: IPage) => page.id === this.targetPageId) ||
this.data[0]
);
}
@computed
get targetWidget() {
return this.data.widgetList.find(
(widget) => widget.id === this.targetWidgetId
return this.targetPage.widgetList.find(
(widget: IWrappedWidget) => widget.id === this.targetWidgetId
);
}
// 添加页面
addPage() {
let newPage = pageGen();
this.data.push(newPage);
this.choosePage(newPage.id);
}
// 修改页面属性
@action
changePageProps = (obj: ChangedObj) => {
mutateValueByPath(this.targetPage.attr, obj);
};
// 修改当前组件属性
@action
changeTargetProps = (style: CSSProperties) => {
this.data.widgetList.find(
(widget) => widget.id === this.targetWidgetId
).style = style;
console.log(
this.data.widgetList.find((widget) => widget.id === this.targetWidgetId)
);
changeTargetProps = (obj: ChangedObj) => {
mutateValueByPath(this.targetWidget, obj);
};
// 根据id修改组件属性
changePagePropsById(pageId: string, obj: ChangedObj) {}
// 根据id修改组件属性
changeWidgetPropsById(widgetId: string, obj: ChangedObj, pageId?: string) {
let targetPage = pageId
? this.data.find((page) => page.id == pageId)
: this.targetPage;
let targetWidget = targetPage.widgetList.find(
(widget) => widget.id === widgetId
);
mutateValueByPath(targetWidget, obj);
}
// 复制组件
@action
copyWidget(targetId: string): void {
let newWidget = cloneDeep(this.targetWidget);
// 重新更改id
newWidget.id = uuidGen();
// 重命名
newWidget.name += '-copy';
// 重新设置位置
newWidget.style.top = getNumber(newWidget.style.top) + 20 + 'px';
newWidget.style.left = getNumber(newWidget.style.left) + 20 + 'px';
this.addWidget(newWidget);
}
// 添加组件
@action
addWidget(wrappedWidget: IWrappedWidget): void {
this.data.widgetList.push(wrappedWidget);
this.targetPage.widgetList.push(wrappedWidget);
}
// 删除当前选中组件
@action
removeCurrWidget() {
const index = this.targetPage.widgetList.findIndex(
(widget) => widget.id === this.targetWidgetId
);
if (index !== -1) {
this.targetWidgetId = '';
this.targetPage.widgetList.splice(index, 1);
}
}
// 设置焦点
// 根据targetId删除组件
@action
removeItemById = (widgetId: string) => {
const index = this.targetPage.widgetList.findIndex(
(widget) => widget.id === widgetId
);
if (index !== -1) {
this.targetWidgetId = '';
this.targetPage.widgetList.splice(index, 1);
}
};
// 选中页面
@action
choosePage = (id: string) => {
this.targetPageId = id;
};
// 选中组件
@action
setFocus(id: string): void {
chooseWidget(id: string): void {
this.targetWidgetId = id;
}
@action
reset() {
this.data = [pageGen()];
this.targetWidgetId = '';
}
}
import {
IPage,
IWidget,
IWrappedWidget,
IPageLayoutTypes,
ChangedObj,
} from '../shared/interfaces';
import { uuidGen } from './uuid';
import { set } from 'lodash-es';
// 获取字符串中连续的数字串
export const getNumber = function getNumber(str) {
export const getNumber = function getNumber(str: string | number): number {
if (typeof str === 'string') {
const arr = str.match(/[-|0-9][0-9]*/);
return arr && arr[0] ? parseInt(arr[0], 10) : 0;
......@@ -7,3 +16,67 @@ export const getNumber = function getNumber(str) {
return str;
}
};
export const getDeg = function getDeg(
centerX: number,
centerY: number,
mouseX: number,
mouseY: number,
offsetDeg = 0
) {
var x = Math.abs(centerX - mouseX);
var y = Math.abs(centerY - mouseY);
var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
var cos = y / z;
var radina = Math.acos(cos); // 用反三角函数求弧度
var deg = Math.floor(180 / (Math.PI / radina)); // 将弧度转换成角度
if (mouseX > centerX && mouseY > centerY) {
// 第四象限
deg = 180 - deg;
}
if (mouseX === centerX && mouseY > centerY) {
// y轴负方向
deg = 180;
}
if (mouseX > centerX && mouseY === centerY) {
// x轴正方向
deg = 90;
}
if (mouseX < centerX && mouseY > centerY) {
// 第三象限
deg = 180 + deg;
}
if (mouseX < centerX && mouseY === centerY) {
// x轴负方向
deg = 270;
}
if (mouseX < centerX && mouseY < centerY) {
// 第二象限
deg = 360 - deg;
}
return deg + offsetDeg;
};
export const mutateValueByPath = (target: any, obj: ChangedObj) => {
Object.keys(obj).forEach((key) => {
set(target, key, obj[key]);
});
};
// 初始化page数据
export const pageGen = (name?: string): IPage => {
return {
id: uuidGen(),
name: name,
attr: {
style: { width: '100px' },
id: '',
name: '',
layout: IPageLayoutTypes.Absolute,
},
widgetList: [],
};
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment