蛙蛙推荐:用VML做思维管理工具
摘要:应该大多数人用过MindManger和OneNote等软件,他们用来描述你的想法,做会议记录,工作笔记等,在界面的任何地方都可以写上文字,并可以拖动,而且文字之间还可以用线连接起来,甚至还有手绘涂鸦功能。
思路:IE很早就支持VML了,可以在网页上画矢量图形,而且和javascript能很好的交互,然后捕获用户的鼠标键盘等事件做相应的处理就可以了。
关于VML的入门及提高,大家可以搜索美洲豹的《Thinking in VML》及沐缘华的《VML极道编程》
先截图看看
使用介绍如下:
1、在网页的任何空白处用鼠标左键拖动可以涂鸦,便于临时记录一些文字;
2、在网页的任何空白处双击鼠标左键,会显示一个可编辑框,编辑框的浅黄色部分可以输入文字(鼠标会变成可输入形状),点击左上角的+/-图标可以展开和收缩文字,用鼠标拖动编辑框上部淡蓝色的部分(鼠标会变成可拖动形状)可以把文字框拖动到别的地方。
3、用鼠标左键点击某一个编辑框的淡蓝色部分,按住Shift键不放,拖拽到另一个编辑框,会在两个编辑框之间画一条线,然后再移动编辑框,这条线会跟着动。用来表示两条关联的信息。
4、点击铅笔笔记、连接曲线、编辑框,会变成选中状态,其边框会编程虚线,然后按delete键可以删除
5、两个编辑框之间的连接曲线可以选中后用鼠标拖动以改变曲度,按住alt键拖动是变化第2个控制点,不按alt键是变化贝塞尔曲线的第1个控制点。
[bug]
!解决了不能拖动滚动条的bug
!物体超出浏览器后,整个坐标系不准确了,而且画布不能超出浏览器区域。
罗列了一些需要增加的功能点,周末实现一下,大家还有什么新需求,觉得很有必要的,也提一下。
我在IE6,IE7下测试通过,有同学反映IE8下不能运行,大家也帮忙测试一下,我没有IE8环境,我的2003安装不上。
todo:
1、删除连接线、编辑框、手绘线==ok
2、改变画笔粗度和颜色
3、编辑框的格式化功能,加粗,字体大小、颜色等
4、两个编辑框之间的连线应该显示箭头,要不知道两个编辑框的关系
5、改变编辑框的图标和颜色,以表示不同的重要性和类别
6、按tab键自动添加兄弟节点,按回车自动添加子节点
完整代码如下
< html xmlns:v ="urn:schemas-microsoft-com:vml" xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > WawaMind beta v1.0 </ title >
</ head >
< style type ="text/css" >
v/:* { BEHAVIOR : url(#default#VML) }
body {
margin-left : 0px ;
margin-top : 0px ;
margin-right : 0px ;
margin-bottom : 0px ;
cursor : default ;
width : 1000px ;
}
.wen {
padding-top : 3px ;
padding-left : 3px ;
padding-bottom : 3px ;
padding-right : 3px ;
FONT-SIZE : 9.2pt ; LINE-HEIGHT : 20px ;
BACKGROUND-COLOR : #99ccff ;
BORDER-BOTTOM : #330099 1px solid ;
BORDER-LEFT : #330099 1px solid ;
BORDER-RIGHT : #330099 1px solid ;
BORDER-TOP : #330099 1px solid ;
/* filter:Alpha(Opacity="80",FinishOpacity="90",Style="0"); */
cursor : move ;
z-index : 100 ;
}
.editdiv
{
OVERFLOW : auto ; background-color : #fff999 ; cursor : default ;
height : 50px ;
}
.editdiv p
{
margin : 0 ;
}
.expanbutton
{
cursor : hand ; font-weight : bold ; font-size : 20px ;
}
</ style >
< script type ="text/javascript" >
var xx = 0 ,yy = 0 ,oldvalue = "" ,poly1,zz = 1
// 有关移动的过程和函数
var dragapproved = false
var eventsource,x,y
var popeventsource = ""
var Pencil = true ;
var selectObj,selectObjBorder = null ;
// 页面双击创建编辑框
function dbClick() {
if (event.srcElement.className != " body " ) return ;
var markhtml = " <div class='wen' style='position:absolute;left: " + window.event.offsetX + " ;top: " + window.event.offsetY + " ;width:150px;z-index:9'></div> " ;
var newMark = document.createElement(markhtml);
document.body.appendChild (newMark);
newMark.innerHTML = " <span class=/ " expanbutton/ " onclick=/ " expandMemo( this )/ " >-</span><span></span><div class=/ " editdiv/ " contentEditable=true onselectstart=/ " event.cancelBubble = true / " ></div> " ;
newMark.fromline = new Array();
newMark.toline = new Array();
}
// 鼠标按下
function msDown() {
if (event.button == 1 ){
var isclickScroll = (event.y < 0 || event.y > document.body.clientHeight
|| event.x < 0 || event.x > document.body.clientWidth)
if (selectObj){ // 清空选择
selectObj.style.borderStyle = selectObjBorder;
selectObj = null ;
}
if (event.srcElement.className == " wen " ||
event.srcElement.tagName == " curve " ||
event.srcElement.tagName == " shape "
) // 选择要删除的对象
{
selectObj = event.srcElement;
selectObjBorder = selectObj.style.borderStyle;
selectObj.style.borderStyle = " dotted " ;
selectObj.style.borderWidth = " 1px " ;
}
if (event.srcElement.className == " wen " )
{
if (event.shiftKey) // 画两个物体间的线
{
eventsource = event.srcElement;
return ;
}
dragapproved = true // 拖动物体
eventsource = event.srcElement
temp1 = eventsource.style.pixelLeft
temp2 = eventsource.style.pixelTop
x = event.clientX
y = event.clientY
} else { // 铅笔
dragapproved = false ;
if (event.srcElement.className != " body " || isclickScroll) // 防止在物体上画线
{
Pencil = false ;
return ;
}
Pencil = true ;
document.body.setCapture();
color1 = " red "
size1 = 1
xx = event.offsetX;yy = event.offsetY;zz += 1
poly1 = document.body.appendChild(document.createElement( " <v:shape filled=false path='m0,0 l0,0' style='position:absolute;z-index: " + zz + " ;left: " + xx + " ;top: " + yy + " ;width:100;height:100' strokecolor=' " + color1 + " ' strokeweight=' " + size1 + " ' coordsize='100,100'/> " ))
oldvalue = poly1.path.value.replace( " e " , "" )
}
}
}
// 鼠标移动
function msMove() {
if (event.button == 1 )
{
if (event.shiftKey) // 画两个物体件的线
{
return ;
}
if (dragapproved){ // 拖动物体
var newleft = temp1 + event.clientX - x
var newtop = temp2 + event.clientY - y
eventsource.style.pixelLeft = newleft
eventsource.style.pixelTop = newtop
// 移动线
for ( var i = 0 ; i < eventsource.fromline.length;i ++ )
{
eventsource.fromline[i].from = newleft + " , " + newtop;
}
for ( var i = 0 ; i < eventsource.toline.length;i ++ )
{
eventsource.toline[i].to = newleft + " , " + newtop;
}
}
else if (selectObj && selectObj.tagName == " curve " )
{ // 调整曲线
if ( ! event.altKey)
selectObj.control1 = event.x + " , " + event.y;
else
selectObj.control2 = event.x + " , " + event.y;
}
else { // 铅笔功能
if (event.srcElement.className != " body " ) return ; // 防止在物体上画线
if (Pencil)
{
oldvalue += " , " + (event.offsetX - xx) + " , " + (event.offsetY - yy);
poly1.path.value = oldvalue
poly1.path.value = poly1.path.value.replace( " ,0, " , " , " ).replace( " ,0 e " , " e " )
}
}
}
}
// 鼠标弹起
function msUp() {
document.body.releaseCapture();
if (event.shiftKey && event.srcElement.className == " wen " ) // 画两个物体见的连线。
{
var target = event.srcElement;
var newline = document.createElement( " <v:curve filled=/ " false / " from= " + eventsource.style.pixelLeft + " , " + eventsource.style.pixelTop + " / " to = / "" + target.style.pixelLeft + " , " + target.style.pixelTop + " / " >< / v:curve>");
document.body.insertBefore(newline);
eventsource.fromline[eventsource.fromline.length] = newline;
target.toline[target.toline.length] = newline;
}
}
// 控制编辑框的展开和收缩
function expandMemo(o)
{
var expand = o.innerText == " + " ;
var text = o.parentNode.childNodes[ 2 ].innerText;
o.parentNode.childNodes[ 1 ].innerText = expand ? "" :text.substring( 0 , 10 );
o.parentNode.childNodes[ 2 ].style.display = expand ? ' block ' : ' none ' ;
o.innerText = expand ? " - " : " + " ;
}
function keyDown() {
if (event.keyCode == 46 ) // 删除
{
if (selectObj)
{
document.body.removeChild(selectObj);
selectObj = null ;
}
}
}
document.onkeydown = keyDown
</ script >
< body class ="body" ondblclick ="dbClick()" onmousedown ="msDown()" onmousemove ="msMove()" onmouseup ="msUp()" onselectstart ="return false;" >
</ body >
</ html >
在地址栏里输入如下文本可以查看运行时生成的html
javascript:document.body.innerHTML%20=%20"<textarea%20style='height:300;%20width:300'>"+document.body.innerHTML+"</textarea>"
或者大家可以用这些代码做一个在线创作脑图的网站,我觉得这东西不一定做的功能多么强大,尽量在简单易用和满足需求之间找到平衡就可以了,我觉得现在的功能能满足我的需求。
winform的工具做好了,欢迎大家下载适应,并反馈信息,周末比较忙,新增功能暂时不做了,另外就是c#的WebBrowser控件为什么只显示竖滚动条,不显示横向滚动条呀,不解决这个问题,画的东西超过画布宽度的话就画不出去了显示不了了。
以下是下载地址。
WawaMind.zip
[参考链接]
记录鼠标轨迹生成vml曲线图程序(可模拟签名)
http://blog.csdn.net/manyou/archive/2005/09/28/491036.aspx
VML打造动态曲线[建议加精]
http://bbs.51js.com/viewthread.php?tid=21639&extra=page%3D1%26amp%3Bfilter%3Ddigest
VML实现铅笔功能?
http://bbs.51js.com/viewthread.php?tid=80191&extra=page%3D1
Javascript技术之详尽解析event对象
http://javascript.chinahtml.com/2007/Javascriptjavascript-118033875213857_3.shtml
How the Javascript Vector Engine Works
http://www.xmlpitstop.com/ArticleManagement/DisplayArticle.aspx?ResourceID=24
[翻译] 6个优秀的思维导图网站
http://bbs.kafan.cn/thread-312112-1-6.html
JavaScript键盘事件侦听
http://www.blogjava.net/zhangrenquan/articles/60110.html
在BODY用onSelectStart=return false 不让选择,但是页面上的文字输入框怎样可以设置到可选择.
http://topic.csdn.net/t/20030112/17/1351341.html
JavaScript高级测试题-你真的了解JavaScript?
http://www.ad0.cn/netfetch/read.php/1173.htm
用 Javascript 获取滚动条位置等信息
http://www.codebit.cn/pub/html/javascript/tip/get_scroll_position/