mirror of https://github.com/fantasticit/think.git
tiptap: add center method in mind
parent
08860dffee
commit
2e6a013203
|
@ -0,0 +1,3 @@
|
||||||
|
interface Window {
|
||||||
|
kityminder: any;
|
||||||
|
}
|
|
@ -7,14 +7,15 @@ import styles from './style.module.scss';
|
||||||
interface IProps {
|
interface IProps {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
onChange: (arg: { width: number; height: number }) => void;
|
onChange?: (arg: { width: number; height: number }) => void;
|
||||||
|
onChangeEnd?: (arg: { width: number; height: number }) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MIN_WIDTH = 50;
|
const MIN_WIDTH = 50;
|
||||||
const MIN_HEIGHT = 50;
|
const MIN_HEIGHT = 50;
|
||||||
|
|
||||||
export const Resizeable: React.FC<IProps> = ({ width, height, className, onChange, children }) => {
|
export const Resizeable: React.FC<IProps> = ({ width, height, className, onChange, onChangeEnd, children }) => {
|
||||||
const $container = useRef<HTMLDivElement>(null);
|
const $container = useRef<HTMLDivElement>(null);
|
||||||
const $topLeft = useRef<HTMLDivElement>(null);
|
const $topLeft = useRef<HTMLDivElement>(null);
|
||||||
const $topRight = useRef<HTMLDivElement>(null);
|
const $topRight = useRef<HTMLDivElement>(null);
|
||||||
|
@ -52,6 +53,10 @@ export const Resizeable: React.FC<IProps> = ({ width, height, className, onChang
|
||||||
Object.assign(event.target.dataset, { x, y });
|
Object.assign(event.target.dataset, { x, y });
|
||||||
onChange && onChange({ width, height });
|
onChange && onChange({ width, height });
|
||||||
},
|
},
|
||||||
|
end: function (event) {
|
||||||
|
let { width, height } = event.rect;
|
||||||
|
onChangeEnd && onChangeEnd({ width, height });
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
|
@ -51,6 +51,10 @@ export const Mind = Node.create({
|
||||||
default: 100,
|
default: 100,
|
||||||
parseHTML: getDatasetAttribute('zoom'),
|
parseHTML: getDatasetAttribute('zoom'),
|
||||||
},
|
},
|
||||||
|
callCenterCount: {
|
||||||
|
default: 0,
|
||||||
|
parseHTML: (element) => Number(getDatasetAttribute('callcentercount')(element)),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { Space, Button, List, Popover, Typography, RadioGroup, Radio } from '@douyinfe/semi-ui';
|
import { Space, Button, Popover, Typography } from '@douyinfe/semi-ui';
|
||||||
import { IconEdit, IconDelete } from '@douyinfe/semi-icons';
|
import { IconAlignCenter, IconDelete } from '@douyinfe/semi-icons';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { IconStructure, IconDrawBoard, IconZoomIn, IconZoomOut } from 'components/icons';
|
import { IconStructure, IconDrawBoard, IconZoomIn, IconZoomOut } from 'components/icons';
|
||||||
import { BubbleMenu } from '../../views/bubble-menu';
|
import { BubbleMenu } from '../../views/bubble-menu';
|
||||||
|
@ -15,7 +14,7 @@ import styles from './bubble.module.scss';
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
export const MindBubbleMenu = ({ editor }) => {
|
export const MindBubbleMenu = ({ editor }) => {
|
||||||
const { template, theme, zoom } = editor.getAttributes(Mind.name);
|
const { template, theme, zoom, callCenterCount } = editor.getAttributes(Mind.name);
|
||||||
|
|
||||||
const setZoom = useCallback(
|
const setZoom = useCallback(
|
||||||
(type: 'minus' | 'plus') => {
|
(type: 'minus' | 'plus') => {
|
||||||
|
@ -32,6 +31,18 @@ export const MindBubbleMenu = ({ editor }) => {
|
||||||
[editor, zoom]
|
[editor, zoom]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const setCenter = useCallback(() => {
|
||||||
|
const nextValue = Number.isNaN(callCenterCount) ? 1 : Number(callCenterCount) + 1;
|
||||||
|
|
||||||
|
editor
|
||||||
|
.chain()
|
||||||
|
.updateAttributes(Mind.name, {
|
||||||
|
callCenterCount: nextValue,
|
||||||
|
})
|
||||||
|
.focus()
|
||||||
|
.run();
|
||||||
|
}, [editor, callCenterCount]);
|
||||||
|
|
||||||
const setTemplate = useCallback(
|
const setTemplate = useCallback(
|
||||||
(template) => {
|
(template) => {
|
||||||
editor
|
editor
|
||||||
|
@ -91,6 +102,11 @@ export const MindBubbleMenu = ({ editor }) => {
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip content="居中">
|
||||||
|
<Button size="small" type="tertiary" theme="borderless" icon={<IconAlignCenter />} onClick={setCenter} />
|
||||||
|
</Tooltip>
|
||||||
|
<Divider />
|
||||||
|
|
||||||
<Popover
|
<Popover
|
||||||
zIndex={10000}
|
zIndex={10000}
|
||||||
spacing={10}
|
spacing={10}
|
||||||
|
@ -103,6 +119,7 @@ export const MindBubbleMenu = ({ editor }) => {
|
||||||
{TEMPLATES.map((item) => {
|
{TEMPLATES.map((item) => {
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
|
key={item.label}
|
||||||
className={cls(template === item.value && styles.active)}
|
className={cls(template === item.value && styles.active)}
|
||||||
onClick={() => setTemplate(item.value)}
|
onClick={() => setTemplate(item.value)}
|
||||||
>
|
>
|
||||||
|
@ -130,6 +147,7 @@ export const MindBubbleMenu = ({ editor }) => {
|
||||||
{THEMES.map((item) => {
|
{THEMES.map((item) => {
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
|
key={item.label}
|
||||||
className={cls(theme === item.value && styles.active)}
|
className={cls(theme === item.value && styles.active)}
|
||||||
style={item.style || {}}
|
style={item.style || {}}
|
||||||
onClick={() => setTheme(item.value)}
|
onClick={() => setTheme(item.value)}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { NodeViewWrapper } from '@tiptap/react';
|
import { NodeViewWrapper } from '@tiptap/react';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { useCallback, useEffect, useRef } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { Spin, Button } from '@douyinfe/semi-ui';
|
import { Spin, Button, Typography } from '@douyinfe/semi-ui';
|
||||||
import { IconMinus, IconPlus } from '@douyinfe/semi-icons';
|
import { IconMinus, IconPlus, IconAlignCenter } from '@douyinfe/semi-icons';
|
||||||
import { Resizeable } from 'components/resizeable';
|
|
||||||
import deepEqual from 'deep-equal';
|
import deepEqual from 'deep-equal';
|
||||||
|
import { Resizeable } from 'components/resizeable';
|
||||||
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import { MIN_ZOOM, MAX_ZOOM, ZOOM_STEP } from '../../menus/mind/constant';
|
import { MIN_ZOOM, MAX_ZOOM, ZOOM_STEP } from '../../menus/mind/constant';
|
||||||
import { clamp } from '../../utils/clamp';
|
import { clamp } from '../../utils/clamp';
|
||||||
|
@ -12,21 +13,54 @@ import { Mind } from '../../extensions/mind';
|
||||||
import { loadKityMinder } from './kityminder';
|
import { loadKityMinder } from './kityminder';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const $container = useRef();
|
const $container = useRef();
|
||||||
const $mind = useRef<any>();
|
const $mind = useRef<any>();
|
||||||
const isMindActive = editor.isActive(Mind.name);
|
const isMindActive = editor.isActive(Mind.name);
|
||||||
const isEditable = editor.isEditable;
|
const isEditable = editor.isEditable;
|
||||||
const { data, template, theme, zoom, width, height = 100 } = node.attrs;
|
const { data, template, theme, zoom, callCenterCount, width, height } = node.attrs;
|
||||||
const [loading, toggleLoading] = useToggle(true);
|
const [loading, toggleLoading] = useToggle(true);
|
||||||
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
|
||||||
|
const content = useMemo(() => {
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '100%', height: '100%' }}>
|
||||||
|
<Text>{error.message || error}</Text>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <Spin spinning={loading} style={{ width: '100%', height: '100%' }}></Spin>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={$container}
|
||||||
|
className={cls(styles.renderWrap, 'render-wrapper')}
|
||||||
|
tabIndex={0}
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
|
></div>
|
||||||
|
);
|
||||||
|
}, [loading, error]);
|
||||||
|
|
||||||
const onResize = useCallback(
|
const onResize = useCallback(
|
||||||
(size) => {
|
(size) => {
|
||||||
updateAttributes({ width: size.width, height: size.height });
|
updateAttributes({ width: size.width, height: size.height });
|
||||||
|
setCenter();
|
||||||
},
|
},
|
||||||
[updateAttributes]
|
[updateAttributes]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const setCenter = useCallback(() => {
|
||||||
|
const minder = $mind.current;
|
||||||
|
if (!minder) return;
|
||||||
|
minder.execCommand('camera');
|
||||||
|
}, []);
|
||||||
|
|
||||||
const setZoom = useCallback(
|
const setZoom = useCallback(
|
||||||
(type: 'minus' | 'plus') => {
|
(type: 'minus' | 'plus') => {
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -50,30 +84,46 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
updateAttributes({ data: minder.exportJson() });
|
updateAttributes({ data: minder.exportJson() });
|
||||||
}, [updateAttributes]);
|
}, [updateAttributes]);
|
||||||
|
|
||||||
// 初始化
|
// 加载依赖
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
loadKityMinder()
|
||||||
|
.then(() => {
|
||||||
|
toggleLoading(false);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
setError(e);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 初始化渲染
|
||||||
|
useEffect(() => {
|
||||||
|
if (loading || !$container.current) return;
|
||||||
|
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
saveData();
|
saveData();
|
||||||
};
|
};
|
||||||
loadKityMinder().then((Editor) => {
|
|
||||||
toggleLoading(false);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const minder = new Editor($container.current).minder;
|
const Editor = window.kityminder.Editor;
|
||||||
minder.importJson(data);
|
const minder = new Editor($container.current).minder;
|
||||||
$mind.current = minder;
|
minder.importJson(data);
|
||||||
minder.on('contentChange', onChange);
|
minder.execCommand('template', template);
|
||||||
} catch (e) {
|
minder.execCommand('theme', theme);
|
||||||
//
|
minder.execCommand('zoom', parseInt(zoom));
|
||||||
}
|
|
||||||
});
|
$mind.current = minder;
|
||||||
|
minder.on('contentChange', onChange);
|
||||||
|
toggleLoading(false);
|
||||||
|
} catch (e) {
|
||||||
|
setError(e);
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if ($mind.current) {
|
if ($mind.current) {
|
||||||
$mind.current.off('contentChange', onChange);
|
$mind.current.off('contentChange', onChange);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [toggleLoading]);
|
}, [loading]);
|
||||||
|
|
||||||
// 数据同步渲染
|
// 数据同步渲染
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -82,7 +132,9 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const currentData = minder.exportJson();
|
const currentData = minder.exportJson();
|
||||||
const isEqual = deepEqual(currentData, data);
|
const isEqual = deepEqual(currentData, data);
|
||||||
if (isEqual) return;
|
if (isEqual) return;
|
||||||
minder.importData(data);
|
|
||||||
|
// TODO: 也许刷新更好些
|
||||||
|
minder.importJson(data);
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
// 布局
|
// 布局
|
||||||
|
@ -118,21 +170,15 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
}
|
}
|
||||||
}, [isEditable]);
|
}, [isEditable]);
|
||||||
|
|
||||||
const content = loading ? (
|
// 居中
|
||||||
<Spin spinning={loading} style={{ width: '100%', height: '100%' }}></Spin>
|
useEffect(() => {
|
||||||
) : (
|
setCenter();
|
||||||
<div
|
}, [callCenterCount]);
|
||||||
ref={$container}
|
|
||||||
className={cls(styles.renderWrap, 'render-wrapper')}
|
|
||||||
tabIndex={0}
|
|
||||||
style={{ width: '100%', height: '100%' }}
|
|
||||||
></div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeViewWrapper className={cls(styles.wrap, isMindActive && styles.isActive)}>
|
<NodeViewWrapper className={cls(styles.wrap, isMindActive && styles.isActive)}>
|
||||||
{isEditable ? (
|
{isEditable ? (
|
||||||
<Resizeable width={width} height={height} onChange={onResize}>
|
<Resizeable width={width} height={height} onChangeEnd={onResize}>
|
||||||
{content}
|
{content}
|
||||||
</Resizeable>
|
</Resizeable>
|
||||||
) : (
|
) : (
|
||||||
|
@ -141,20 +187,33 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
|
|
||||||
{!isEditable && (
|
{!isEditable && (
|
||||||
<div className={styles.mindHandlerWrap}>
|
<div className={styles.mindHandlerWrap}>
|
||||||
<Button
|
<Tooltip content="缩小">
|
||||||
size="small"
|
<Button
|
||||||
theme="borderless"
|
size="small"
|
||||||
type="tertiary"
|
theme="borderless"
|
||||||
icon={<IconMinus style={{ fontSize: 14 }} />}
|
type="tertiary"
|
||||||
onClick={setZoom('minus')}
|
icon={<IconMinus style={{ fontSize: 14 }} />}
|
||||||
/>
|
onClick={setZoom('minus')}
|
||||||
<Button
|
/>
|
||||||
size="small"
|
</Tooltip>
|
||||||
theme="borderless"
|
<Tooltip content="放大">
|
||||||
type="tertiary"
|
<Button
|
||||||
icon={<IconPlus style={{ fontSize: 14 }} />}
|
size="small"
|
||||||
onClick={setZoom('plus')}
|
theme="borderless"
|
||||||
/>
|
type="tertiary"
|
||||||
|
icon={<IconPlus style={{ fontSize: 14 }} />}
|
||||||
|
onClick={setZoom('plus')}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip content="居中">
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
theme="borderless"
|
||||||
|
type="tertiary"
|
||||||
|
icon={<IconAlignCenter style={{ fontSize: 14 }} />}
|
||||||
|
onClick={setCenter}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</NodeViewWrapper>
|
</NodeViewWrapper>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,11 @@
|
||||||
export const loadKityMinder = async (): Promise<any> => {
|
export const loadKityMinder = async (): Promise<any> => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
if (window.kityminder) {
|
||||||
|
if (window.kityminder.Editor) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await import('kity');
|
await import('kity');
|
||||||
await import('./kity-core/kityminder');
|
await import('./kity-core/kityminder');
|
||||||
await import('./kity-editor/expose-editor');
|
await import('./kity-editor/expose-editor');
|
||||||
|
|
||||||
const Editor = (window as any).kityminder.Editor;
|
|
||||||
|
|
||||||
return Editor;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,151 +1,149 @@
|
||||||
define(function(require, exports, module) {
|
define(function (require, exports, module) {
|
||||||
var kity = require('./kity');
|
var kity = require('./kity');
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var Minder = require('./minder');
|
var Minder = require('./minder');
|
||||||
|
|
||||||
/* 已注册的模块 */
|
/* 已注册的模块 */
|
||||||
var _modules = {};
|
var _modules = {};
|
||||||
|
|
||||||
exports.register = function(name, module) {
|
exports.register = function (name, module) {
|
||||||
_modules[name] = module;
|
_modules[name] = module;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 模块初始化 */
|
/* 模块初始化 */
|
||||||
Minder.registerInitHook(function() {
|
Minder.registerInitHook(function () {
|
||||||
this._initModules();
|
this._initModules();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 模块声明周期维护
|
// 模块声明周期维护
|
||||||
kity.extendClass(Minder, {
|
kity.extendClass(Minder, {
|
||||||
_initModules: function() {
|
_initModules: function () {
|
||||||
var modulesPool = _modules;
|
var modulesPool = _modules;
|
||||||
var modulesToLoad = this._options.modules || utils.keys(modulesPool);
|
var modulesToLoad = this._options.modules || utils.keys(modulesPool);
|
||||||
|
|
||||||
this._commands = {};
|
this._commands = {};
|
||||||
this._query = {};
|
this._query = {};
|
||||||
this._modules = {};
|
this._modules = {};
|
||||||
this._rendererClasses = {};
|
this._rendererClasses = {};
|
||||||
|
|
||||||
var i, name, type, module, moduleDeals,
|
var i, name, type, module, moduleDeals, dealCommands, dealEvents, dealRenderers;
|
||||||
dealCommands, dealEvents, dealRenderers;
|
|
||||||
|
|
||||||
var me = this;
|
var me = this;
|
||||||
for (i = 0; i < modulesToLoad.length; i++) {
|
for (i = 0; i < modulesToLoad.length; i++) {
|
||||||
name = modulesToLoad[i];
|
name = modulesToLoad[i];
|
||||||
|
|
||||||
if (!modulesPool[name]) continue;
|
if (!modulesPool[name]) continue;
|
||||||
|
|
||||||
// 执行模块初始化,抛出后续处理对象
|
// 执行模块初始化,抛出后续处理对象
|
||||||
|
|
||||||
if (typeof(modulesPool[name]) == 'function') {
|
if (typeof modulesPool[name] == 'function') {
|
||||||
moduleDeals = modulesPool[name].call(me);
|
moduleDeals = modulesPool[name].call(me);
|
||||||
} else {
|
} else {
|
||||||
moduleDeals = modulesPool[name];
|
moduleDeals = modulesPool[name];
|
||||||
}
|
|
||||||
this._modules[name] = moduleDeals;
|
|
||||||
|
|
||||||
if (!moduleDeals) continue;
|
|
||||||
|
|
||||||
if (moduleDeals.defaultOptions) {
|
|
||||||
me.setDefaultOptions(moduleDeals.defaultOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moduleDeals.init) {
|
|
||||||
moduleDeals.init.call(me, this._options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Desc: 判断是否支持原生clipboard事件,如果支持,则对pager添加其监听
|
|
||||||
* @Editor: Naixor
|
|
||||||
* @Date: 2015.9.20
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* 由于当前脑图解构问题,clipboard暂时全权交由玩不托管
|
|
||||||
* @Editor: Naixor
|
|
||||||
* @Date: 2015.9.24
|
|
||||||
*/
|
|
||||||
// if (name === 'ClipboardModule' && this.supportClipboardEvent && !kity.Browser.gecko) {
|
|
||||||
// var on = function () {
|
|
||||||
// var clipBoardReceiver = this.clipBoardReceiver || document;
|
|
||||||
|
|
||||||
// if (document.addEventListener) {
|
|
||||||
// clipBoardReceiver.addEventListener.apply(this, arguments);
|
|
||||||
// } else {
|
|
||||||
// arguments[0] = 'on' + arguments[0];
|
|
||||||
// clipBoardReceiver.attachEvent.apply(this, arguments);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// for (var command in moduleDeals.clipBoardEvents) {
|
|
||||||
// on(command, moduleDeals.clipBoardEvents[command]);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// command加入命令池子
|
|
||||||
dealCommands = moduleDeals.commands;
|
|
||||||
for (name in dealCommands) {
|
|
||||||
this._commands[name.toLowerCase()] = new dealCommands[name]();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绑定事件
|
|
||||||
dealEvents = moduleDeals.events;
|
|
||||||
if (dealEvents) {
|
|
||||||
for (type in dealEvents) {
|
|
||||||
me.on(type, dealEvents[type]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 渲染器
|
|
||||||
dealRenderers = moduleDeals.renderers;
|
|
||||||
|
|
||||||
if (dealRenderers) {
|
|
||||||
|
|
||||||
for (type in dealRenderers) {
|
|
||||||
this._rendererClasses[type] = this._rendererClasses[type] || [];
|
|
||||||
|
|
||||||
if (utils.isArray(dealRenderers[type])) {
|
|
||||||
this._rendererClasses[type] = this._rendererClasses[type].concat(dealRenderers[type]);
|
|
||||||
} else {
|
|
||||||
this._rendererClasses[type].push(dealRenderers[type]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//添加模块的快捷键
|
|
||||||
if (moduleDeals.commandShortcutKeys) {
|
|
||||||
this.addCommandShortcutKeys(moduleDeals.commandShortcutKeys);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_garbage: function() {
|
|
||||||
this.clearSelect();
|
|
||||||
|
|
||||||
while (this._root.getChildren().length) {
|
|
||||||
this._root.removeChild(0);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
var modules = this._modules;
|
|
||||||
|
|
||||||
this._resetEvents();
|
|
||||||
this._garbage();
|
|
||||||
|
|
||||||
for (var key in modules) {
|
|
||||||
if (!modules[key].destroy) continue;
|
|
||||||
modules[key].destroy.call(this);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
reset: function() {
|
|
||||||
var modules = this._modules;
|
|
||||||
|
|
||||||
this._garbage();
|
|
||||||
|
|
||||||
for (var key in modules) {
|
|
||||||
if (!modules[key].reset) continue;
|
|
||||||
modules[key].reset.call(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
this._modules[name] = moduleDeals;
|
||||||
|
|
||||||
|
if (!moduleDeals) continue;
|
||||||
|
|
||||||
|
if (moduleDeals.defaultOptions) {
|
||||||
|
me.setDefaultOptions(moduleDeals.defaultOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleDeals.init) {
|
||||||
|
moduleDeals.init.call(me, this._options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: 判断是否支持原生clipboard事件,如果支持,则对pager添加其监听
|
||||||
|
* @Editor: Naixor
|
||||||
|
* @Date: 2015.9.20
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* 由于当前脑图解构问题,clipboard暂时全权交由玩不托管
|
||||||
|
* @Editor: Naixor
|
||||||
|
* @Date: 2015.9.24
|
||||||
|
*/
|
||||||
|
// if (name === 'ClipboardModule' && this.supportClipboardEvent && !kity.Browser.gecko) {
|
||||||
|
// var on = function () {
|
||||||
|
// var clipBoardReceiver = this.clipBoardReceiver || document;
|
||||||
|
|
||||||
|
// if (document.addEventListener) {
|
||||||
|
// clipBoardReceiver.addEventListener.apply(this, arguments);
|
||||||
|
// } else {
|
||||||
|
// arguments[0] = 'on' + arguments[0];
|
||||||
|
// clipBoardReceiver.attachEvent.apply(this, arguments);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// for (var command in moduleDeals.clipBoardEvents) {
|
||||||
|
// on(command, moduleDeals.clipBoardEvents[command]);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// command加入命令池子
|
||||||
|
dealCommands = moduleDeals.commands;
|
||||||
|
for (name in dealCommands) {
|
||||||
|
this._commands[name.toLowerCase()] = new dealCommands[name]();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定事件
|
||||||
|
dealEvents = moduleDeals.events;
|
||||||
|
if (dealEvents) {
|
||||||
|
for (type in dealEvents) {
|
||||||
|
me.on(type, dealEvents[type]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染器
|
||||||
|
dealRenderers = moduleDeals.renderers;
|
||||||
|
|
||||||
|
if (dealRenderers) {
|
||||||
|
for (type in dealRenderers) {
|
||||||
|
this._rendererClasses[type] = this._rendererClasses[type] || [];
|
||||||
|
|
||||||
|
if (utils.isArray(dealRenderers[type])) {
|
||||||
|
this._rendererClasses[type] = this._rendererClasses[type].concat(dealRenderers[type]);
|
||||||
|
} else {
|
||||||
|
this._rendererClasses[type].push(dealRenderers[type]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//添加模块的快捷键
|
||||||
|
if (moduleDeals.commandShortcutKeys) {
|
||||||
|
this.addCommandShortcutKeys(moduleDeals.commandShortcutKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_garbage: function () {
|
||||||
|
// this.clearSelect();
|
||||||
|
|
||||||
|
while (this._root.getChildren().length) {
|
||||||
|
this._root.removeChild(0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function () {
|
||||||
|
var modules = this._modules;
|
||||||
|
|
||||||
|
this._resetEvents();
|
||||||
|
this._garbage();
|
||||||
|
|
||||||
|
for (var key in modules) {
|
||||||
|
if (!modules[key].destroy) continue;
|
||||||
|
modules[key].destroy.call(this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function () {
|
||||||
|
var modules = this._modules;
|
||||||
|
|
||||||
|
this._garbage();
|
||||||
|
|
||||||
|
for (var key in modules) {
|
||||||
|
if (!modules[key].reset) continue;
|
||||||
|
modules[key].reset.call(this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -1,92 +1,101 @@
|
||||||
define(function(require, exports, module) {
|
define(function (require, exports, module) {
|
||||||
var kity = require('./kity');
|
var kity = require('./kity');
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var Minder = require('./minder');
|
var Minder = require('./minder');
|
||||||
var Command = require('./command');
|
var Command = require('./command');
|
||||||
var MinderNode = require('./node');
|
var MinderNode = require('./node');
|
||||||
var Module = require('./module');
|
var Module = require('./module');
|
||||||
|
|
||||||
var _templates = {};
|
var _templates = {};
|
||||||
|
|
||||||
function register(name, supports) {
|
function register(name, supports) {
|
||||||
_templates[name] = supports;
|
_templates[name] = supports;
|
||||||
}
|
}
|
||||||
exports.register = register;
|
exports.register = register;
|
||||||
|
|
||||||
utils.extend(Minder, {
|
utils.extend(Minder, {
|
||||||
getTemplateList: function() {
|
getTemplateList: function () {
|
||||||
return _templates;
|
return _templates;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
kity.extendClass(Minder, (function() {
|
kity.extendClass(
|
||||||
var originGetTheme = Minder.prototype.getTheme;
|
Minder,
|
||||||
return {
|
(function () {
|
||||||
useTemplate: function(name, duration) {
|
var originGetTheme = Minder.prototype.getTheme;
|
||||||
this.setTemplate(name);
|
return {
|
||||||
this.refresh(duration || 800);
|
useTemplate: function (name, duration) {
|
||||||
},
|
this.setTemplate(name);
|
||||||
|
this.refresh(duration || 500);
|
||||||
|
},
|
||||||
|
|
||||||
getTemplate: function() {
|
getTemplate: function () {
|
||||||
return this._template || 'default';
|
return this._template || 'default';
|
||||||
},
|
},
|
||||||
|
|
||||||
setTemplate: function(name) {
|
setTemplate: function (name) {
|
||||||
this._template = name || null;
|
this._template = name || null;
|
||||||
},
|
},
|
||||||
|
|
||||||
getTemplateSupport: function(method) {
|
getTemplateSupport: function (method) {
|
||||||
var supports = _templates[this.getTemplate()];
|
var supports = _templates[this.getTemplate()];
|
||||||
return supports && supports[method];
|
return supports && supports[method];
|
||||||
},
|
},
|
||||||
|
|
||||||
getTheme: function(node) {
|
getTheme: function (node) {
|
||||||
var support = this.getTemplateSupport('getTheme') || originGetTheme;
|
var support = this.getTemplateSupport('getTheme') || originGetTheme;
|
||||||
return support.call(this, node);
|
return support.call(this, node);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
})());
|
})()
|
||||||
|
);
|
||||||
|
|
||||||
|
kity.extendClass(
|
||||||
|
MinderNode,
|
||||||
|
(function () {
|
||||||
|
var originGetLayout = MinderNode.prototype.getLayout;
|
||||||
|
var originGetConnect = MinderNode.prototype.getConnect;
|
||||||
|
return {
|
||||||
|
getLayout: function () {
|
||||||
|
var support = this.getMinder().getTemplateSupport('getLayout') || originGetLayout;
|
||||||
|
return support.call(this, this);
|
||||||
|
},
|
||||||
|
|
||||||
kity.extendClass(MinderNode, (function() {
|
getConnect: function () {
|
||||||
var originGetLayout = MinderNode.prototype.getLayout;
|
var support = this.getMinder().getTemplateSupport('getConnect') || originGetConnect;
|
||||||
var originGetConnect = MinderNode.prototype.getConnect;
|
return support.call(this, this);
|
||||||
return {
|
},
|
||||||
getLayout: function() {
|
};
|
||||||
var support = this.getMinder().getTemplateSupport('getLayout') || originGetLayout;
|
})()
|
||||||
return support.call(this, this);
|
);
|
||||||
},
|
let timer = null;
|
||||||
|
|
||||||
getConnect: function() {
|
Module.register('TemplateModule', {
|
||||||
var support = this.getMinder().getTemplateSupport('getConnect') || originGetConnect;
|
/**
|
||||||
return support.call(this, this);
|
* @command Template
|
||||||
}
|
* @description 设置当前脑图的模板
|
||||||
};
|
* @param {string} name 模板名称
|
||||||
})());
|
* 允许使用的模板可以使用 `kityminder.Minder.getTemplateList()` 查询
|
||||||
|
* @state
|
||||||
|
* 0: 始终可用
|
||||||
|
* @return 返回当前的模板名称
|
||||||
|
*/
|
||||||
|
commands: {
|
||||||
|
template: kity.createClass('TemplateCommand', {
|
||||||
|
base: Command,
|
||||||
|
|
||||||
Module.register('TemplateModule', {
|
execute: function (minder, name) {
|
||||||
/**
|
minder.useTemplate(name);
|
||||||
* @command Template
|
clearTimeout(timer);
|
||||||
* @description 设置当前脑图的模板
|
timer = setTimeout(() => {
|
||||||
* @param {string} name 模板名称
|
minder.execCommand('camera');
|
||||||
* 允许使用的模板可以使用 `kityminder.Minder.getTemplateList()` 查询
|
}, 550);
|
||||||
* @state
|
},
|
||||||
* 0: 始终可用
|
|
||||||
* @return 返回当前的模板名称
|
|
||||||
*/
|
|
||||||
commands: {
|
|
||||||
'template': kity.createClass('TemplateCommand', {
|
|
||||||
base: Command,
|
|
||||||
|
|
||||||
execute: function(minder, name) {
|
queryValue: function (minder) {
|
||||||
minder.useTemplate(name);
|
return minder.getTemplate() || 'default';
|
||||||
minder.execCommand('camera');
|
},
|
||||||
},
|
}),
|
||||||
|
},
|
||||||
queryValue: function(minder) {
|
});
|
||||||
return minder.getTemplate() || 'default';
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
|
@ -1,397 +1,403 @@
|
||||||
define(function(require, exports, module) {
|
define(function (require, exports, module) {
|
||||||
var kity = require('../core/kity');
|
var kity = require('../core/kity');
|
||||||
var utils = require('../core/utils');
|
var utils = require('../core/utils');
|
||||||
|
|
||||||
var Minder = require('../core/minder');
|
var Minder = require('../core/minder');
|
||||||
var MinderNode = require('../core/node');
|
var MinderNode = require('../core/node');
|
||||||
var Command = require('../core/command');
|
var Command = require('../core/command');
|
||||||
var Module = require('../core/module');
|
var Module = require('../core/module');
|
||||||
var Renderer = require('../core/render');
|
var Renderer = require('../core/render');
|
||||||
|
|
||||||
var ViewDragger = kity.createClass('ViewDragger', {
|
var ViewDragger = kity.createClass('ViewDragger', {
|
||||||
constructor: function(minder) {
|
constructor: function (minder) {
|
||||||
this._minder = minder;
|
this._minder = minder;
|
||||||
this._enabled = false;
|
this._enabled = false;
|
||||||
this._bind();
|
this._bind();
|
||||||
var me = this;
|
var me = this;
|
||||||
this._minder.getViewDragger = function() {
|
this._minder.getViewDragger = function () {
|
||||||
return me;
|
return me;
|
||||||
};
|
};
|
||||||
this.setEnabled(false);
|
this.setEnabled(false);
|
||||||
},
|
},
|
||||||
|
|
||||||
isEnabled: function() {
|
isEnabled: function () {
|
||||||
return this._enabled;
|
return this._enabled;
|
||||||
},
|
},
|
||||||
|
|
||||||
setEnabled: function(value) {
|
setEnabled: function (value) {
|
||||||
var paper = this._minder.getPaper();
|
var paper = this._minder.getPaper();
|
||||||
paper.setStyle('cursor', value ? 'pointer' : 'default');
|
paper.setStyle('cursor', value ? 'pointer' : 'default');
|
||||||
paper.setStyle('cursor', value ? '-webkit-grab' : 'default');
|
paper.setStyle('cursor', value ? '-webkit-grab' : 'default');
|
||||||
this._enabled = value;
|
this._enabled = value;
|
||||||
},
|
},
|
||||||
timeline: function() {
|
timeline: function () {
|
||||||
return this._moveTimeline;
|
return this._moveTimeline;
|
||||||
},
|
},
|
||||||
|
|
||||||
move: function(offset, duration) {
|
move: function (offset, duration) {
|
||||||
var minder = this._minder;
|
var minder = this._minder;
|
||||||
|
|
||||||
var targetPosition = this.getMovement().offset(offset);
|
var targetPosition = this.getMovement().offset(offset);
|
||||||
|
|
||||||
this.moveTo(targetPosition, duration);
|
this.moveTo(targetPosition, duration);
|
||||||
},
|
},
|
||||||
|
|
||||||
moveTo: function(position, duration) {
|
moveTo: function (position, duration) {
|
||||||
|
if (duration) {
|
||||||
|
var dragger = this;
|
||||||
|
|
||||||
if (duration) {
|
if (this._moveTimeline) this._moveTimeline.stop();
|
||||||
var dragger = this;
|
|
||||||
|
|
||||||
if (this._moveTimeline) this._moveTimeline.stop();
|
this._moveTimeline = this._minder
|
||||||
|
.getRenderContainer()
|
||||||
|
.animate(
|
||||||
|
new kity.Animator(this.getMovement(), position, function (target, value) {
|
||||||
|
dragger.moveTo(value);
|
||||||
|
}),
|
||||||
|
duration,
|
||||||
|
'easeOutCubic'
|
||||||
|
)
|
||||||
|
.timeline();
|
||||||
|
|
||||||
this._moveTimeline = this._minder.getRenderContainer().animate(new kity.Animator(
|
this._moveTimeline.on('finish', function () {
|
||||||
this.getMovement(),
|
dragger._moveTimeline = null;
|
||||||
position,
|
});
|
||||||
function(target, value) {
|
|
||||||
dragger.moveTo(value);
|
|
||||||
}
|
|
||||||
), duration, 'easeOutCubic').timeline();
|
|
||||||
|
|
||||||
this._moveTimeline.on('finish', function() {
|
return this;
|
||||||
dragger._moveTimeline = null;
|
}
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
this._minder.getRenderContainer().setTranslate(position.round());
|
||||||
}
|
this._minder.fire('viewchange');
|
||||||
|
},
|
||||||
|
|
||||||
this._minder.getRenderContainer().setTranslate(position.round());
|
getMovement: function () {
|
||||||
this._minder.fire('viewchange');
|
var translate = this._minder.getRenderContainer().transform.translate;
|
||||||
},
|
return translate ? translate[0] : new kity.Point();
|
||||||
|
},
|
||||||
|
|
||||||
getMovement: function() {
|
getView: function () {
|
||||||
var translate = this._minder.getRenderContainer().transform.translate;
|
var minder = this._minder;
|
||||||
return translate ? translate[0] : new kity.Point();
|
var c = minder._lastClientSize || {
|
||||||
},
|
width: minder.getRenderTarget().clientWidth,
|
||||||
|
height: minder.getRenderTarget().clientHeight,
|
||||||
|
};
|
||||||
|
var m = this.getMovement();
|
||||||
|
var box = new kity.Box(0, 0, c.width, c.height);
|
||||||
|
var viewMatrix = minder.getPaper().getViewPortMatrix();
|
||||||
|
return viewMatrix.inverse().translate(-m.x, -m.y).transformBox(box);
|
||||||
|
},
|
||||||
|
|
||||||
getView: function() {
|
_bind: function () {
|
||||||
var minder = this._minder;
|
var dragger = this,
|
||||||
var c = minder._lastClientSize || {
|
isTempDrag = false,
|
||||||
width: minder.getRenderTarget().clientWidth,
|
lastPosition = null,
|
||||||
height: minder.getRenderTarget().clientHeight
|
currentPosition = null;
|
||||||
};
|
|
||||||
var m = this.getMovement();
|
|
||||||
var box = new kity.Box(0, 0, c.width, c.height);
|
|
||||||
var viewMatrix = minder.getPaper().getViewPortMatrix();
|
|
||||||
return viewMatrix.inverse().translate(-m.x, -m.y).transformBox(box);
|
|
||||||
},
|
|
||||||
|
|
||||||
_bind: function() {
|
function dragEnd(e) {
|
||||||
var dragger = this,
|
if (!lastPosition) return;
|
||||||
isTempDrag = false,
|
|
||||||
lastPosition = null,
|
|
||||||
currentPosition = null;
|
|
||||||
|
|
||||||
function dragEnd(e) {
|
lastPosition = null;
|
||||||
if (!lastPosition) return;
|
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
lastPosition = null;
|
// 临时拖动需要还原状态
|
||||||
|
if (isTempDrag) {
|
||||||
e.stopPropagation();
|
dragger.setEnabled(false);
|
||||||
|
isTempDrag = false;
|
||||||
// 临时拖动需要还原状态
|
if (dragger._minder.getStatus() == 'hand') dragger._minder.rollbackStatus();
|
||||||
if (isTempDrag) {
|
|
||||||
dragger.setEnabled(false);
|
|
||||||
isTempDrag = false;
|
|
||||||
if (dragger._minder.getStatus() == 'hand')
|
|
||||||
dragger._minder.rollbackStatus();
|
|
||||||
}
|
|
||||||
var paper = dragger._minder.getPaper();
|
|
||||||
paper.setStyle('cursor', dragger._minder.getStatus() == 'hand' ? '-webkit-grab' : 'default');
|
|
||||||
|
|
||||||
dragger._minder.fire('viewchanged');
|
|
||||||
}
|
|
||||||
|
|
||||||
this._minder.on('normal.mousedown normal.touchstart ' +
|
|
||||||
'inputready.mousedown inputready.touchstart ' +
|
|
||||||
'readonly.mousedown readonly.touchstart',
|
|
||||||
function(e) {
|
|
||||||
if (e.originEvent.button == 2) {
|
|
||||||
e.originEvent.preventDefault(); // 阻止中键拉动
|
|
||||||
}
|
|
||||||
// 点击未选中的根节点临时开启
|
|
||||||
if (e.getTargetNode() == this.getRoot() || e.originEvent.button == 2 || e.originEvent.altKey) {
|
|
||||||
lastPosition = e.getPosition('view');
|
|
||||||
isTempDrag = true;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
.on('normal.mousemove normal.touchmove ' +
|
|
||||||
'readonly.mousemove readonly.touchmove ' +
|
|
||||||
'inputready.mousemove inputready.touchmove',
|
|
||||||
function(e) {
|
|
||||||
if (e.type == 'touchmove') {
|
|
||||||
e.preventDefault(); // 阻止浏览器的后退事件
|
|
||||||
}
|
|
||||||
if (!isTempDrag) return;
|
|
||||||
var offset = kity.Vector.fromPoints(lastPosition, e.getPosition('view'));
|
|
||||||
if (offset.length() > 10) {
|
|
||||||
this.setStatus('hand', true);
|
|
||||||
var paper = dragger._minder.getPaper();
|
|
||||||
paper.setStyle('cursor', '-webkit-grabbing');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
.on('hand.beforemousedown hand.beforetouchstart', function(e) {
|
|
||||||
// 已经被用户打开拖放模式
|
|
||||||
if (dragger.isEnabled()) {
|
|
||||||
lastPosition = e.getPosition('view');
|
|
||||||
e.stopPropagation();
|
|
||||||
var paper = dragger._minder.getPaper();
|
|
||||||
paper.setStyle('cursor', '-webkit-grabbing');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
.on('hand.beforemousemove hand.beforetouchmove', function(e) {
|
|
||||||
if (lastPosition) {
|
|
||||||
currentPosition = e.getPosition('view');
|
|
||||||
|
|
||||||
// 当前偏移加上历史偏移
|
|
||||||
var offset = kity.Vector.fromPoints(lastPosition, currentPosition);
|
|
||||||
dragger.move(offset);
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
e.originEvent.preventDefault();
|
|
||||||
lastPosition = currentPosition;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
.on('mouseup touchend', dragEnd);
|
|
||||||
|
|
||||||
window.addEventListener('mouseup', dragEnd);
|
|
||||||
this._minder.on('contextmenu', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
var paper = dragger._minder.getPaper();
|
||||||
|
paper.setStyle('cursor', dragger._minder.getStatus() == 'hand' ? '-webkit-grab' : 'default');
|
||||||
|
|
||||||
Module.register('View', function() {
|
dragger._minder.fire('viewchanged');
|
||||||
|
}
|
||||||
|
|
||||||
var km = this;
|
this._minder
|
||||||
|
.on(
|
||||||
/**
|
'normal.mousedown normal.touchstart ' +
|
||||||
* @command Hand
|
'inputready.mousedown inputready.touchstart ' +
|
||||||
* @description 切换抓手状态,抓手状态下,鼠标拖动将拖动视野,而不是创建选区
|
'readonly.mousedown readonly.touchstart',
|
||||||
* @state
|
function (e) {
|
||||||
* 0: 当前不是抓手状态
|
if (e.originEvent.button == 2) {
|
||||||
* 1: 当前是抓手状态
|
e.originEvent.preventDefault(); // 阻止中键拉动
|
||||||
*/
|
|
||||||
var ToggleHandCommand = kity.createClass('ToggleHandCommand', {
|
|
||||||
base: Command,
|
|
||||||
execute: function(minder) {
|
|
||||||
|
|
||||||
if (minder.getStatus() != 'hand') {
|
|
||||||
minder.setStatus('hand', true);
|
|
||||||
} else {
|
|
||||||
minder.rollbackStatus();
|
|
||||||
}
|
|
||||||
this.setContentChanged(false);
|
|
||||||
|
|
||||||
},
|
|
||||||
queryState: function(minder) {
|
|
||||||
return minder.getStatus() == 'hand' ? 1 : 0;
|
|
||||||
},
|
|
||||||
enableReadOnly: true
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @command Camera
|
|
||||||
* @description 设置当前视野的中心位置到某个节点上
|
|
||||||
* @param {kityminder.MinderNode} focusNode 要定位的节点
|
|
||||||
* @param {number} duration 设置视野移动的动画时长(单位 ms),设置为 0 不使用动画
|
|
||||||
* @state
|
|
||||||
* 0: 始终可用
|
|
||||||
*/
|
|
||||||
var CameraCommand = kity.createClass('CameraCommand', {
|
|
||||||
base: Command,
|
|
||||||
execute: function(km, focusNode) {
|
|
||||||
|
|
||||||
focusNode = focusNode || km.getRoot();
|
|
||||||
var viewport = km.getPaper().getViewPort();
|
|
||||||
var offset = focusNode.getRenderContainer().getRenderBox('view');
|
|
||||||
var dx = viewport.center.x - offset.x - offset.width / 2,
|
|
||||||
dy = viewport.center.y - offset.y;
|
|
||||||
var dragger = km._viewDragger;
|
|
||||||
|
|
||||||
var duration = km.getOption('viewAnimationDuration');
|
|
||||||
dragger.move(new kity.Point(dx, dy), duration);
|
|
||||||
this.setContentChanged(false);
|
|
||||||
},
|
|
||||||
enableReadOnly: true
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @command Move
|
|
||||||
* @description 指定方向移动当前视野
|
|
||||||
* @param {string} dir 移动方向
|
|
||||||
* 取值为 'left',视野向左移动一半
|
|
||||||
* 取值为 'right',视野向右移动一半
|
|
||||||
* 取值为 'up',视野向上移动一半
|
|
||||||
* 取值为 'down',视野向下移动一半
|
|
||||||
* @param {number} duration 视野移动的动画时长(单位 ms),设置为 0 不使用动画
|
|
||||||
* @state
|
|
||||||
* 0: 始终可用
|
|
||||||
*/
|
|
||||||
var MoveCommand = kity.createClass('MoveCommand', {
|
|
||||||
base: Command,
|
|
||||||
|
|
||||||
execute: function(km, dir) {
|
|
||||||
var dragger = km._viewDragger;
|
|
||||||
var size = km._lastClientSize;
|
|
||||||
var duration = km.getOption('viewAnimationDuration');
|
|
||||||
switch (dir) {
|
|
||||||
case 'up':
|
|
||||||
dragger.move(new kity.Point(0, size.height / 2), duration);
|
|
||||||
break;
|
|
||||||
case 'down':
|
|
||||||
dragger.move(new kity.Point(0, -size.height / 2), duration);
|
|
||||||
break;
|
|
||||||
case 'left':
|
|
||||||
dragger.move(new kity.Point(size.width / 2, 0), duration);
|
|
||||||
break;
|
|
||||||
case 'right':
|
|
||||||
dragger.move(new kity.Point(-size.width / 2, 0), duration);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
enableReadOnly: true
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
init: function() {
|
|
||||||
this._viewDragger = new ViewDragger(this);
|
|
||||||
},
|
|
||||||
commands: {
|
|
||||||
'hand': ToggleHandCommand,
|
|
||||||
'camera': CameraCommand,
|
|
||||||
'move': MoveCommand
|
|
||||||
},
|
|
||||||
events: {
|
|
||||||
statuschange: function(e) {
|
|
||||||
this._viewDragger.setEnabled(e.currentStatus == 'hand');
|
|
||||||
},
|
|
||||||
mousewheel: function(e) {
|
|
||||||
var dx, dy;
|
|
||||||
e = e.originEvent;
|
|
||||||
if (e.ctrlKey || e.shiftKey) return;
|
|
||||||
if ('wheelDeltaX' in e) {
|
|
||||||
|
|
||||||
dx = e.wheelDeltaX || 0;
|
|
||||||
dy = e.wheelDeltaY || 0;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
dx = 0;
|
|
||||||
dy = e.wheelDelta;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
this._viewDragger.move({
|
|
||||||
x: dx / 2.5,
|
|
||||||
y: dy / 2.5
|
|
||||||
});
|
|
||||||
|
|
||||||
var me = this;
|
|
||||||
clearTimeout(this._mousewheeltimer);
|
|
||||||
this._mousewheeltimer = setTimeout(function() {
|
|
||||||
me.fire('viewchanged');
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
},
|
|
||||||
'normal.dblclick readonly.dblclick': function(e) {
|
|
||||||
if (e.kityEvent.targetShape instanceof kity.Paper) {
|
|
||||||
this.execCommand('camera', this.getRoot(), 800);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'paperrender finishInitHook': function() {
|
|
||||||
if (!this.getRenderTarget()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.execCommand('camera', null, 0);
|
|
||||||
this._lastClientSize = {
|
|
||||||
width: this.getRenderTarget().clientWidth,
|
|
||||||
height: this.getRenderTarget().clientHeight
|
|
||||||
};
|
|
||||||
},
|
|
||||||
resize: function(e) {
|
|
||||||
var a = {
|
|
||||||
width: this.getRenderTarget().clientWidth,
|
|
||||||
height: this.getRenderTarget().clientHeight
|
|
||||||
},
|
|
||||||
b = this._lastClientSize;
|
|
||||||
this._viewDragger.move(
|
|
||||||
new kity.Point((a.width - b.width) / 2 | 0, (a.height - b.height) / 2 | 0));
|
|
||||||
this._lastClientSize = a;
|
|
||||||
},
|
|
||||||
'selectionchange layoutallfinish': function(e) {
|
|
||||||
var selected = this.getSelectedNode();
|
|
||||||
var minder = this;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Added by zhangbobell 2015.9.9
|
|
||||||
* windows 10 的 edge 浏览器在全部动画停止后,优先级图标不显示 text,
|
|
||||||
* 因此再次触发一次 render 事件,让浏览器重绘
|
|
||||||
* */
|
|
||||||
if (kity.Browser.edge) {
|
|
||||||
this.fire('paperrender');
|
|
||||||
}
|
|
||||||
if (!selected) return;
|
|
||||||
|
|
||||||
var dragger = this._viewDragger;
|
|
||||||
var timeline = dragger.timeline();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Added by zhangbobell 2015.09.25
|
|
||||||
* 如果之前有动画,那么就先暂时返回,等之前动画结束之后再次执行本函数
|
|
||||||
* 以防止 view 动画变动了位置,导致本函数执行的时候位置计算不对
|
|
||||||
*
|
|
||||||
* fixed bug : 初始化的时候中心节点位置不固定(有的时候在左上角,有的时候在中心)
|
|
||||||
* */
|
|
||||||
if (timeline){
|
|
||||||
timeline.on('finish', function() {
|
|
||||||
minder.fire('selectionchange');
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var view = dragger.getView();
|
|
||||||
var focus = selected.getLayoutBox();
|
|
||||||
var space = 50;
|
|
||||||
var dx = 0, dy = 0;
|
|
||||||
|
|
||||||
if (focus.right > view.right) {
|
|
||||||
dx += view.right - focus.right - space;
|
|
||||||
}
|
|
||||||
else if (focus.left < view.left) {
|
|
||||||
dx += view.left - focus.left + space;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (focus.bottom > view.bottom) {
|
|
||||||
dy += view.bottom - focus.bottom - space;
|
|
||||||
}
|
|
||||||
if (focus.top < view.top) {
|
|
||||||
dy += view.top - focus.top + space;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dx || dy) dragger.move(new kity.Point(dx, dy), 100);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
// 点击未选中的根节点临时开启
|
||||||
|
if (e.getTargetNode() == this.getRoot() || e.originEvent.button == 2 || e.originEvent.altKey) {
|
||||||
|
lastPosition = e.getPosition('view');
|
||||||
|
isTempDrag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
.on(
|
||||||
|
'normal.mousemove normal.touchmove ' +
|
||||||
|
'readonly.mousemove readonly.touchmove ' +
|
||||||
|
'inputready.mousemove inputready.touchmove',
|
||||||
|
function (e) {
|
||||||
|
if (e.type == 'touchmove') {
|
||||||
|
e.preventDefault(); // 阻止浏览器的后退事件
|
||||||
|
}
|
||||||
|
if (!isTempDrag) return;
|
||||||
|
var offset = kity.Vector.fromPoints(lastPosition, e.getPosition('view'));
|
||||||
|
if (offset.length() > 10) {
|
||||||
|
this.setStatus('hand', true);
|
||||||
|
var paper = dragger._minder.getPaper();
|
||||||
|
paper.setStyle('cursor', '-webkit-grabbing');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
.on('hand.beforemousedown hand.beforetouchstart', function (e) {
|
||||||
|
// 已经被用户打开拖放模式
|
||||||
|
if (dragger.isEnabled()) {
|
||||||
|
lastPosition = e.getPosition('view');
|
||||||
|
e.stopPropagation();
|
||||||
|
var paper = dragger._minder.getPaper();
|
||||||
|
paper.setStyle('cursor', '-webkit-grabbing');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('hand.beforemousemove hand.beforetouchmove', function (e) {
|
||||||
|
if (lastPosition) {
|
||||||
|
currentPosition = e.getPosition('view');
|
||||||
|
|
||||||
|
// 当前偏移加上历史偏移
|
||||||
|
var offset = kity.Vector.fromPoints(lastPosition, currentPosition);
|
||||||
|
dragger.move(offset);
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
e.originEvent.preventDefault();
|
||||||
|
lastPosition = currentPosition;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('mouseup touchend', dragEnd);
|
||||||
|
|
||||||
|
window.addEventListener('mouseup', dragEnd);
|
||||||
|
this._minder.on('contextmenu', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Module.register('View', function () {
|
||||||
|
var km = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @command Hand
|
||||||
|
* @description 切换抓手状态,抓手状态下,鼠标拖动将拖动视野,而不是创建选区
|
||||||
|
* @state
|
||||||
|
* 0: 当前不是抓手状态
|
||||||
|
* 1: 当前是抓手状态
|
||||||
|
*/
|
||||||
|
var ToggleHandCommand = kity.createClass('ToggleHandCommand', {
|
||||||
|
base: Command,
|
||||||
|
execute: function (minder) {
|
||||||
|
if (minder.getStatus() != 'hand') {
|
||||||
|
minder.setStatus('hand', true);
|
||||||
|
} else {
|
||||||
|
minder.rollbackStatus();
|
||||||
|
}
|
||||||
|
this.setContentChanged(false);
|
||||||
|
},
|
||||||
|
queryState: function (minder) {
|
||||||
|
return minder.getStatus() == 'hand' ? 1 : 0;
|
||||||
|
},
|
||||||
|
enableReadOnly: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @command Camera
|
||||||
|
* @description 设置当前视野的中心位置到某个节点上
|
||||||
|
* @param {kityminder.MinderNode} focusNode 要定位的节点
|
||||||
|
* @param {number} duration 设置视野移动的动画时长(单位 ms),设置为 0 不使用动画
|
||||||
|
* @state
|
||||||
|
* 0: 始终可用
|
||||||
|
*/
|
||||||
|
var CameraCommand = kity.createClass('CameraCommand', {
|
||||||
|
base: Command,
|
||||||
|
execute: function (km, focusNode) {
|
||||||
|
const dragger = km._viewDragger;
|
||||||
|
const duration = km.getOption('viewAnimationDuration');
|
||||||
|
let dx = 0;
|
||||||
|
let dy = 0;
|
||||||
|
|
||||||
|
if (!focusNode || focusNode.type === 'root') {
|
||||||
|
// 默认居中
|
||||||
|
const parentNode = km.getPaper().node;
|
||||||
|
const shapeNode = km.getRoot().rc.container.node;
|
||||||
|
const { width: pw, height: ph, x: px, y: py } = parentNode.getBoundingClientRect();
|
||||||
|
const { width: sw, height: sh, x, y } = shapeNode.getBBox();
|
||||||
|
dx = pw / 2 - x - sw / 2;
|
||||||
|
dy = ph / 2 - y - sh / 2;
|
||||||
|
dragger.moveTo(new kity.Point(dx, dy), duration);
|
||||||
|
} else {
|
||||||
|
var viewport = km.getPaper().getViewPort();
|
||||||
|
var offset = focusNode.getRenderContainer().getRenderBox('view');
|
||||||
|
dx = viewport.center.x - offset.x - offset.width / 2;
|
||||||
|
dy = viewport.center.y - offset.y;
|
||||||
|
dragger.move(new kity.Point(dx, dy), duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setContentChanged(false);
|
||||||
|
},
|
||||||
|
enableReadOnly: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @command Move
|
||||||
|
* @description 指定方向移动当前视野
|
||||||
|
* @param {string} dir 移动方向
|
||||||
|
* 取值为 'left',视野向左移动一半
|
||||||
|
* 取值为 'right',视野向右移动一半
|
||||||
|
* 取值为 'up',视野向上移动一半
|
||||||
|
* 取值为 'down',视野向下移动一半
|
||||||
|
* @param {number} duration 视野移动的动画时长(单位 ms),设置为 0 不使用动画
|
||||||
|
* @state
|
||||||
|
* 0: 始终可用
|
||||||
|
*/
|
||||||
|
var MoveCommand = kity.createClass('MoveCommand', {
|
||||||
|
base: Command,
|
||||||
|
|
||||||
|
execute: function (km, dir) {
|
||||||
|
var dragger = km._viewDragger;
|
||||||
|
var size = km._lastClientSize;
|
||||||
|
var duration = km.getOption('viewAnimationDuration');
|
||||||
|
switch (dir) {
|
||||||
|
case 'up':
|
||||||
|
dragger.move(new kity.Point(0, size.height / 2), duration);
|
||||||
|
break;
|
||||||
|
case 'down':
|
||||||
|
dragger.move(new kity.Point(0, -size.height / 2), duration);
|
||||||
|
break;
|
||||||
|
case 'left':
|
||||||
|
dragger.move(new kity.Point(size.width / 2, 0), duration);
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
dragger.move(new kity.Point(-size.width / 2, 0), duration);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
enableReadOnly: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: function () {
|
||||||
|
this._viewDragger = new ViewDragger(this);
|
||||||
|
},
|
||||||
|
commands: {
|
||||||
|
hand: ToggleHandCommand,
|
||||||
|
camera: CameraCommand,
|
||||||
|
move: MoveCommand,
|
||||||
|
},
|
||||||
|
events: {
|
||||||
|
'statuschange': function (e) {
|
||||||
|
this._viewDragger.setEnabled(e.currentStatus == 'hand');
|
||||||
|
},
|
||||||
|
'mousewheel': function (e) {
|
||||||
|
var dx, dy;
|
||||||
|
e = e.originEvent;
|
||||||
|
if (e.ctrlKey || e.shiftKey) return;
|
||||||
|
if ('wheelDeltaX' in e) {
|
||||||
|
dx = e.wheelDeltaX || 0;
|
||||||
|
dy = e.wheelDeltaY || 0;
|
||||||
|
} else {
|
||||||
|
dx = 0;
|
||||||
|
dy = e.wheelDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._viewDragger.move({
|
||||||
|
x: dx / 2.5,
|
||||||
|
y: dy / 2.5,
|
||||||
|
});
|
||||||
|
|
||||||
|
var me = this;
|
||||||
|
clearTimeout(this._mousewheeltimer);
|
||||||
|
this._mousewheeltimer = setTimeout(function () {
|
||||||
|
me.fire('viewchanged');
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
},
|
||||||
|
'normal.dblclick readonly.dblclick': function (e) {
|
||||||
|
if (e.kityEvent.targetShape instanceof kity.Paper) {
|
||||||
|
this.execCommand('camera', this.getRoot(), 800);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'paperrender finishInitHook': function () {
|
||||||
|
if (!this.getRenderTarget()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.execCommand('camera', null, 0);
|
||||||
|
this._lastClientSize = {
|
||||||
|
width: this.getRenderTarget().clientWidth,
|
||||||
|
height: this.getRenderTarget().clientHeight,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
'resize': function (e) {
|
||||||
|
var a = {
|
||||||
|
width: this.getRenderTarget().clientWidth,
|
||||||
|
height: this.getRenderTarget().clientHeight,
|
||||||
|
},
|
||||||
|
b = this._lastClientSize;
|
||||||
|
this._viewDragger.move(new kity.Point(((a.width - b.width) / 2) | 0, ((a.height - b.height) / 2) | 0));
|
||||||
|
this._lastClientSize = a;
|
||||||
|
},
|
||||||
|
'selectionchange layoutallfinish': function (e) {
|
||||||
|
var selected = this.getSelectedNode();
|
||||||
|
var minder = this;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Added by zhangbobell 2015.9.9
|
||||||
|
* windows 10 的 edge 浏览器在全部动画停止后,优先级图标不显示 text,
|
||||||
|
* 因此再次触发一次 render 事件,让浏览器重绘
|
||||||
|
* */
|
||||||
|
if (kity.Browser.edge) {
|
||||||
|
this.fire('paperrender');
|
||||||
|
}
|
||||||
|
if (!selected) return;
|
||||||
|
|
||||||
|
var dragger = this._viewDragger;
|
||||||
|
var timeline = dragger.timeline();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Added by zhangbobell 2015.09.25
|
||||||
|
* 如果之前有动画,那么就先暂时返回,等之前动画结束之后再次执行本函数
|
||||||
|
* 以防止 view 动画变动了位置,导致本函数执行的时候位置计算不对
|
||||||
|
*
|
||||||
|
* fixed bug : 初始化的时候中心节点位置不固定(有的时候在左上角,有的时候在中心)
|
||||||
|
* */
|
||||||
|
if (timeline) {
|
||||||
|
timeline.on('finish', function () {
|
||||||
|
minder.fire('selectionchange');
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var view = dragger.getView();
|
||||||
|
var focus = selected.getLayoutBox();
|
||||||
|
var space = 50;
|
||||||
|
var dx = 0,
|
||||||
|
dy = 0;
|
||||||
|
|
||||||
|
if (focus.right > view.right) {
|
||||||
|
dx += view.right - focus.right - space;
|
||||||
|
} else if (focus.left < view.left) {
|
||||||
|
dx += view.left - focus.left + space;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (focus.bottom > view.bottom) {
|
||||||
|
dy += view.bottom - focus.bottom - space;
|
||||||
|
}
|
||||||
|
if (focus.top < view.top) {
|
||||||
|
dy += view.top - focus.top + space;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dx || dy) dragger.move(new kity.Point(dx, dy), 100);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
|
@ -30,6 +30,6 @@
|
||||||
"event/*": ["event/*"]
|
"event/*": ["event/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
"include": ["next-env.d.ts", "global.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue