研究了几天javascipt,真是个又老又奇怪又有用的语言。很想实现一个web上可用的拓扑,以前做过一点网管软件外围的web报表系统,有客户很想用浏览器来看topo图,并且希望在浏览器中就可以看到被管对象图示的告警闪烁,当时能做的就是摇头。个人认为桌面应用很多都能移植到web上,也能有很好的交互,虽然难度很大。受各式各样webGIS的启发,试着把topo搬到浏览器中,目前看来是完全可能的。最主要的还是实现拖拽和边界判定,至于数据可以使用ajax技术从服务端获取,服务端用什么都行j2ee,.net,php,怎么着都行。拖拽还是借鉴了netvibes的思路,链路使用VML是google map的思路(FF下用svg),目前只支持IE,FF的以后再说。
// 寻找对象的绝对X坐标
function findPosX(obj) {
var curleft = 0;
if (obj.offsetParent) {
while (obj.offsetParent) {
curleft += obj.offsetLeft;
obj = obj.offsetParent;
}
} else if (obj.x) curleft += obj.x;
return curleft;
}
// 寻找对象的绝对Y坐标
function findPosY(obj) {
var curtop = 0;
if (obj.offsetParent) {
while (obj.offsetParent) {
curtop += obj.offsetTop;
obj = obj.offsetParent;
}
} else if (obj.y) curtop += obj.y;
return curtop;
}
这里是一个简单客户端的demo截图,还有点样子吧。还存在大量的bug,功能也很有限,服务器端压根还没有写。
CODE:
<defaultTest.htm>
<!
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
>
< html xmlns:v ="urn:schemas-microsoft-com:vml" >
< head >
< STYLE >
v:* { BEHAVIOR: url(#default#VML) }
</ STYLE >
< meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" />
< title > Topo ^-^ </ title >
< link rel ="shortcut icon" href ="favicon.ico" >
< link rel ="stylesheet" type ="text/css" href ="style/styles.css?v=10" media ="screen" />
< script >
var App = new Object();
</ script >
< script src ="js/util.js" type ="text/javascript" ></ script >
< script src ="js/dragTest.js" type ="text/javascript" ></ script >
< script src ="js/Drag.js" type ="text/javascript" ></ script >
</ head >
< body >
< div id ="application" >
< div id ="modulesArea1" style ="border:1px solid #000000; background: #cfcfcf; width: 400px; height:400px; position: absolute; left: 10px; top: 10px;" >
< div id ="modulesArea" style ="border:1px solid #000000; background: #cfcfcf; width: 300px; height:300px; position: absolute; left: 50px; top: 50px;" ></ div >
</ div >
</ div >
< script >
var temp_container = document.getElementById("modulesArea");
var container = {
//容器对象
"container":temp_container,
//容器的绝对X,Y坐标(即以容器边框外边缘距为基准)
"AbsX":findPosX(temp_container),
"AbsY":findPosY(temp_container),
//容器的X,Y坐标(即以容器边框内边缘距为基准)
"X":findPosX(temp_container) + parseInt(temp_container.style.borderLeftWidth),
"Y":findPosY(temp_container) + parseInt(temp_container.style.borderTopWidth),
//容器的绝对宽、高(即包含容器边框)
"AbsWidth":temp_container.offsetWidth,
"AbsHeight":temp_container.offsetHeight,
//容器的宽、高(即不包含容器边框)
"Width":parseInt(temp_container.style.width),
"Height":parseInt(temp_container.style.height),
//容器的左右上下四个边框的宽度
"borderLeftWidth":parseInt(temp_container.style.borderLeftWidth),
"borderRightWidth":parseInt(temp_container.style.borderRightWidth),
"borderTopWidth":parseInt(temp_container.style.borderTopWidth),
"borderBottomWidth":parseInt(temp_container.style.borderBottomWidth),
//计算鼠标的坐标(以容器的边框内边缘左上角为原点)
"getMouseX":function(evClientX){
return evClientX-container.X;
},
"getMouseY":function(evClientY){
return evClientY-container.Y;
}
};
</ script >
</ body >
</ html >
< html xmlns:v ="urn:schemas-microsoft-com:vml" >
< head >
< STYLE >
v:* { BEHAVIOR: url(#default#VML) }
</ STYLE >
< meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" />
< title > Topo ^-^ </ title >
< link rel ="shortcut icon" href ="favicon.ico" >
< link rel ="stylesheet" type ="text/css" href ="style/styles.css?v=10" media ="screen" />
< script >
var App = new Object();
</ script >
< script src ="js/util.js" type ="text/javascript" ></ script >
< script src ="js/dragTest.js" type ="text/javascript" ></ script >
< script src ="js/Drag.js" type ="text/javascript" ></ script >
</ head >
< body >
< div id ="application" >
< div id ="modulesArea1" style ="border:1px solid #000000; background: #cfcfcf; width: 400px; height:400px; position: absolute; left: 10px; top: 10px;" >
< div id ="modulesArea" style ="border:1px solid #000000; background: #cfcfcf; width: 300px; height:300px; position: absolute; left: 50px; top: 50px;" ></ div >
</ div >
</ div >
< script >
var temp_container = document.getElementById("modulesArea");
var container = {
//容器对象
"container":temp_container,
//容器的绝对X,Y坐标(即以容器边框外边缘距为基准)
"AbsX":findPosX(temp_container),
"AbsY":findPosY(temp_container),
//容器的X,Y坐标(即以容器边框内边缘距为基准)
"X":findPosX(temp_container) + parseInt(temp_container.style.borderLeftWidth),
"Y":findPosY(temp_container) + parseInt(temp_container.style.borderTopWidth),
//容器的绝对宽、高(即包含容器边框)
"AbsWidth":temp_container.offsetWidth,
"AbsHeight":temp_container.offsetHeight,
//容器的宽、高(即不包含容器边框)
"Width":parseInt(temp_container.style.width),
"Height":parseInt(temp_container.style.height),
//容器的左右上下四个边框的宽度
"borderLeftWidth":parseInt(temp_container.style.borderLeftWidth),
"borderRightWidth":parseInt(temp_container.style.borderRightWidth),
"borderTopWidth":parseInt(temp_container.style.borderTopWidth),
"borderBottomWidth":parseInt(temp_container.style.borderBottomWidth),
//计算鼠标的坐标(以容器的边框内边缘左上角为原点)
"getMouseX":function(evClientX){
return evClientX-container.X;
},
"getMouseY":function(evClientY){
return evClientY-container.Y;
}
};
</ script >
</ body >
</ html >
<js/Drag.js>
var
Drag
=
{
"obj":null,
"init":function(item){
// item: Div元素
item.onmousedown=Drag.start;
item.middleX=item.getX() + parseInt(item.offsetWidth)/2;
item.middleY=item.getY() + parseInt(item.offsetHeight)/2;
},
"start":function(ev){
// ev:事件
var item=Drag.obj=this;
ev=Drag.fixE(ev);
//记录鼠标单击时位置,在一次完整的拖拽的过程中,这个值不变,用于计算被拖拽对象相对与刚开始拖拽时所移动的相对距离。
item.setStartMouseX(ev.clientX);
item.setStartMouseY(ev.clientY);
//记录被拖拽对象刚开始拖拽时的位置,在一次完整的拖拽的过程中,这个值不变,用于计算被拖拽对象在拖拽过程中的位置。
item.setLastX();
item.setLastY();
item.setMiddleX();
item.setMiddleY();
item.onDragStart(item.getX(),item.getY(),item.getStartMouseX(),item.getStartMouseY());
document.onmousemove=Drag.drag;
document.onmouseup=Drag.end;
return false;
},
"drag":function(ev){
// ev:事件
ev=Drag.fixE(ev);
var item=Drag.obj;
var currMouseX=container.getMouseX(ev.clientX);
var currMouseY=container.getMouseY(ev.clientY);
item.setX(currMouseX-item.getStartMouseX()+item.getLastX());
item.setY(currMouseY-item.getStartMouseY()+item.getLastY());
item.setMiddleX();
item.setMiddleY();
item.onDrag(item.getX(),item.getY(),currMouseX,currMouseY);
return false;
},
"end":function(){
document.onmousemove=null;
document.onmouseup=null;
Drag.obj.onDragEnd(Drag.obj.getX(),Drag.obj.getY());
Drag.obj=null;
},
"fixE":function(ev){
// ev:事件
if(typeof ev=="undefined")ev=window.event;
if(typeof ev.layerX=="undefined")ev.layerX=ev.offsetX;
if(typeof ev.layerY=="undefined")ev.layerY=ev.offsetY;
return ev;
}
} ;
"obj":null,
"init":function(item){
// item: Div元素
item.onmousedown=Drag.start;
item.middleX=item.getX() + parseInt(item.offsetWidth)/2;
item.middleY=item.getY() + parseInt(item.offsetHeight)/2;
},
"start":function(ev){
// ev:事件
var item=Drag.obj=this;
ev=Drag.fixE(ev);
//记录鼠标单击时位置,在一次完整的拖拽的过程中,这个值不变,用于计算被拖拽对象相对与刚开始拖拽时所移动的相对距离。
item.setStartMouseX(ev.clientX);
item.setStartMouseY(ev.clientY);
//记录被拖拽对象刚开始拖拽时的位置,在一次完整的拖拽的过程中,这个值不变,用于计算被拖拽对象在拖拽过程中的位置。
item.setLastX();
item.setLastY();
item.setMiddleX();
item.setMiddleY();
item.onDragStart(item.getX(),item.getY(),item.getStartMouseX(),item.getStartMouseY());
document.onmousemove=Drag.drag;
document.onmouseup=Drag.end;
return false;
},
"drag":function(ev){
// ev:事件
ev=Drag.fixE(ev);
var item=Drag.obj;
var currMouseX=container.getMouseX(ev.clientX);
var currMouseY=container.getMouseY(ev.clientY);
item.setX(currMouseX-item.getStartMouseX()+item.getLastX());
item.setY(currMouseY-item.getStartMouseY()+item.getLastY());
item.setMiddleX();
item.setMiddleY();
item.onDrag(item.getX(),item.getY(),currMouseX,currMouseY);
return false;
},
"end":function(){
document.onmousemove=null;
document.onmouseup=null;
Drag.obj.onDragEnd(Drag.obj.getX(),Drag.obj.getY());
Drag.obj=null;
},
"fixE":function(ev){
// ev:事件
if(typeof ev=="undefined")ev=window.event;
if(typeof ev.layerX=="undefined")ev.layerX=ev.offsetX;
if(typeof ev.layerY=="undefined")ev.layerY=ev.offsetY;
return ev;
}
} ;
<js/dragTest.js>
//
var _ZINDEX = 1000 ;
var _ZINDEX_MAX = 2147483647 ;
var _zindex = _ZINDEX;
function coordsX (x, dargObj) {
var maxX = container.Width-dargObj.offsetWidth;
x = x<=0?0:x>=maxX?maxX:x;
return x;
}
function coordsY (y, dargObj) {
var maxY = container.Height-dargObj.offsetHeight;
y = y<=0?0:y>=maxY?maxY:y;
return y;
}
App.Start = function () {
var dragDivs = new Array();
var lines = new Array();
for(var i = 0; i<10; i++){
dragDivs[i] = buildDragDiv(i,i*(35-i),i*(5+i),30,30,1,"#3A3A3A","#E0CB0E");
container.container.appendChild(dragDivs[i]);
Drag.init(dragDivs[i]);
lines[i] = buildLine(2,0,0,200,200,2,"green");
dragDivs[i].bindLine(lines[i],"from");
container.container.appendChild(lines[i]);
}
document.getElementById("application").style.display = "block";
}
// 构造被拖拽DIV对象
//
// id: DIV对象的唯一标识
// x: DIV对象的x坐标(以容器左上角为原点)
// y: DIV对象的y坐标(以容器左上角为原点)
// w: DIV对象宽度(不含边框)
// h: DIV对象高度(不含边框)
// bw: DIV对象边框的宽度
// bc: DIV对象边框的颜色
// bg: DIV对象的颜色(不含边框)
buildDragDiv = function (id,x,y,w,h,bw,bc,bg) {
var item = document.createElement("div");
item.lineObjs = new Array();
item.id=id;
item.style.left=(isNaN(parseInt(x)) ? 0:x) + "px";
item.style.top=(isNaN(parseInt(y)) ? 0:y) + "px";
item.style.width=(isNaN(parseInt(w)) ? 0:w) + "px";
item.style.height=(isNaN(parseInt(h)) ? 0:h) + "px";
item.style.border=(isNaN(parseInt(bw)) ? 1:bw) + "px solid " + ((typeof(bg)=='undefined' || bg.length==0) ? "#3a3a3a":bc);
item.style.background=(typeof(bg)=='undefined' || bg.length==0) ? "#969696":bg;
item.style.cursor="move";
item.style.zIndex=_ZINDEX;
item.style.position = "absolute";
item.borderWidth=isNaN(parseInt(bw)) ? 1:bw;
item.middleX=parseInt(item.style.left) + parseInt(item.style.width)/2 + item.borderWidth;
item.middleY=parseInt(item.style.top) + parseInt(item.style.Height)/2 + item.borderWidth;
item.setMiddleX=function(){
item.middleX=item.getX() + item.offsetWidth/2;
}
item.getMiddleX=function(){
return item.middleX;
}
item.setMiddleY=function(){
item.middleY=item.getY() + item.offsetHeight/2;
}
item.getMiddleY=function(){
return item.middleY;
}
item.setX=function(x){
item.style.left=x + "px";
};
item.getX=function(){
return parseInt(item.style.left);
};
item.setY=function(y){
item.style.top=y + "px";
};
item.getY=function(){
return parseInt(item.style.top);
};
item.startMouseX=0;
item.startMouseY=0;
item.setStartMouseX=function(evClientX){
item.startMouseX=evClientX-container.X;
}
item.getStartMouseX=function(){
return item.startMouseX;
}
item.setStartMouseY=function(evClientY){
item.startMouseY=evClientY-container.Y;
}
item.getStartMouseY=function(){
return item.startMouseY;
}
item.lastX=0;
item.lastY=0;
item.setLastX=function(){
item.lastX=item.getX();
}
item.getLastX=function(){
return item.lastX;
}
item.setLastY=function(){
item.lastY=item.getY();
}
item.getLastY=function(){
return item.lastY;
}
item.setZIndex=function(z_Index){
item.style.zIndex=z_Index;
}
item.onDragStart=function(x,y,mousex, mousey) {
if(item.style.zIndex != _zindex || item.style.zIndex == _ZINDEX){
_zindex += 2;
item.setZIndex(_zindex);
for(var lineObj in this.lineObjs){
this.lineObjs[lineObj].line.style.zIndex=item.style.zIndex-1;
}
}
}
item.onDrag = function(x,y, mousex, mousey) {
this.setX(coordsX(x,this));
this.setY(coordsY(y,this));
item.setMiddleX();
item.setMiddleY();
for(var lineObj in this.lineObjs){
if(this.lineObjs[lineObj].point == "from"){
this.lineObjs[lineObj].line.from = this.getMiddleX() + "," + this.getMiddleY();
}else if(this.lineObjs[lineObj].point == "to"){
this.lineObjs[lineObj].line.to = this.getMiddleX() + "," + this.getMiddleY();
}
}
}
item.onDragEnd = function(x,y) {
this.isDragging = false;
}
item.bindLine=function(line,point){
var lineObj = new LineObj(line,point);
if(point=="from"){
lineObj.line.from=item.getMiddleX() + "," + item.getMiddleY();
}else if(point=="to") {
lineObj.line.to=item.getMiddleX() + "," + item.getMiddleY();
}
item.lineObjs.push(lineObj);
line.style.zIndex=item.style.zIndex-1;
}
return item;
}
LineObj = function (line,point) {
this.line = line;
this.point =point;
}
buildLine = function (id,fromX,fromY,toX,toY,weight,color) {
var line=document.createElement("v:line");
line.id=id;
line.style.position="absolute";
line.style.top="0px";
line.style.left="0px";
line.unselectable="on";
line.strokecolor=(typeof(color)=='undefined' || color.length==0) ? "#000000":color;
line.from = (isNaN(parseInt(fromX)) ? 0:fromX) + "," + (isNaN(parseInt(fromY)) ? 0:fromY);
line.to = (isNaN(parseInt(toX)) ? 0:toX) + "," + (isNaN(parseInt(toY)) ? 0:toY);
line.strokeweight=(isNaN(parseInt(weight)) ? 0:weight) + "pt";
line.fill=false;
line.filled=false;
line.getFrom=function(){
return line.from;
}
line.setFrom=function(x,y){
line.from=x + "," + y;
}
line.getTo=function(){
return line.to;
}
line.setTo=function(x,y){
line.to=x + "," + y;
}
return line;
}
window.onload = function () {
App.Start();
}
var _ZINDEX = 1000 ;
var _ZINDEX_MAX = 2147483647 ;
var _zindex = _ZINDEX;
function coordsX (x, dargObj) {
var maxX = container.Width-dargObj.offsetWidth;
x = x<=0?0:x>=maxX?maxX:x;
return x;
}
function coordsY (y, dargObj) {
var maxY = container.Height-dargObj.offsetHeight;
y = y<=0?0:y>=maxY?maxY:y;
return y;
}
App.Start = function () {
var dragDivs = new Array();
var lines = new Array();
for(var i = 0; i<10; i++){
dragDivs[i] = buildDragDiv(i,i*(35-i),i*(5+i),30,30,1,"#3A3A3A","#E0CB0E");
container.container.appendChild(dragDivs[i]);
Drag.init(dragDivs[i]);
lines[i] = buildLine(2,0,0,200,200,2,"green");
dragDivs[i].bindLine(lines[i],"from");
container.container.appendChild(lines[i]);
}
document.getElementById("application").style.display = "block";
}
// 构造被拖拽DIV对象
//
// id: DIV对象的唯一标识
// x: DIV对象的x坐标(以容器左上角为原点)
// y: DIV对象的y坐标(以容器左上角为原点)
// w: DIV对象宽度(不含边框)
// h: DIV对象高度(不含边框)
// bw: DIV对象边框的宽度
// bc: DIV对象边框的颜色
// bg: DIV对象的颜色(不含边框)
buildDragDiv = function (id,x,y,w,h,bw,bc,bg) {
var item = document.createElement("div");
item.lineObjs = new Array();
item.id=id;
item.style.left=(isNaN(parseInt(x)) ? 0:x) + "px";
item.style.top=(isNaN(parseInt(y)) ? 0:y) + "px";
item.style.width=(isNaN(parseInt(w)) ? 0:w) + "px";
item.style.height=(isNaN(parseInt(h)) ? 0:h) + "px";
item.style.border=(isNaN(parseInt(bw)) ? 1:bw) + "px solid " + ((typeof(bg)=='undefined' || bg.length==0) ? "#3a3a3a":bc);
item.style.background=(typeof(bg)=='undefined' || bg.length==0) ? "#969696":bg;
item.style.cursor="move";
item.style.zIndex=_ZINDEX;
item.style.position = "absolute";
item.borderWidth=isNaN(parseInt(bw)) ? 1:bw;
item.middleX=parseInt(item.style.left) + parseInt(item.style.width)/2 + item.borderWidth;
item.middleY=parseInt(item.style.top) + parseInt(item.style.Height)/2 + item.borderWidth;
item.setMiddleX=function(){
item.middleX=item.getX() + item.offsetWidth/2;
}
item.getMiddleX=function(){
return item.middleX;
}
item.setMiddleY=function(){
item.middleY=item.getY() + item.offsetHeight/2;
}
item.getMiddleY=function(){
return item.middleY;
}
item.setX=function(x){
item.style.left=x + "px";
};
item.getX=function(){
return parseInt(item.style.left);
};
item.setY=function(y){
item.style.top=y + "px";
};
item.getY=function(){
return parseInt(item.style.top);
};
item.startMouseX=0;
item.startMouseY=0;
item.setStartMouseX=function(evClientX){
item.startMouseX=evClientX-container.X;
}
item.getStartMouseX=function(){
return item.startMouseX;
}
item.setStartMouseY=function(evClientY){
item.startMouseY=evClientY-container.Y;
}
item.getStartMouseY=function(){
return item.startMouseY;
}
item.lastX=0;
item.lastY=0;
item.setLastX=function(){
item.lastX=item.getX();
}
item.getLastX=function(){
return item.lastX;
}
item.setLastY=function(){
item.lastY=item.getY();
}
item.getLastY=function(){
return item.lastY;
}
item.setZIndex=function(z_Index){
item.style.zIndex=z_Index;
}
item.onDragStart=function(x,y,mousex, mousey) {
if(item.style.zIndex != _zindex || item.style.zIndex == _ZINDEX){
_zindex += 2;
item.setZIndex(_zindex);
for(var lineObj in this.lineObjs){
this.lineObjs[lineObj].line.style.zIndex=item.style.zIndex-1;
}
}
}
item.onDrag = function(x,y, mousex, mousey) {
this.setX(coordsX(x,this));
this.setY(coordsY(y,this));
item.setMiddleX();
item.setMiddleY();
for(var lineObj in this.lineObjs){
if(this.lineObjs[lineObj].point == "from"){
this.lineObjs[lineObj].line.from = this.getMiddleX() + "," + this.getMiddleY();
}else if(this.lineObjs[lineObj].point == "to"){
this.lineObjs[lineObj].line.to = this.getMiddleX() + "," + this.getMiddleY();
}
}
}
item.onDragEnd = function(x,y) {
this.isDragging = false;
}
item.bindLine=function(line,point){
var lineObj = new LineObj(line,point);
if(point=="from"){
lineObj.line.from=item.getMiddleX() + "," + item.getMiddleY();
}else if(point=="to") {
lineObj.line.to=item.getMiddleX() + "," + item.getMiddleY();
}
item.lineObjs.push(lineObj);
line.style.zIndex=item.style.zIndex-1;
}
return item;
}
LineObj = function (line,point) {
this.line = line;
this.point =point;
}
buildLine = function (id,fromX,fromY,toX,toY,weight,color) {
var line=document.createElement("v:line");
line.id=id;
line.style.position="absolute";
line.style.top="0px";
line.style.left="0px";
line.unselectable="on";
line.strokecolor=(typeof(color)=='undefined' || color.length==0) ? "#000000":color;
line.from = (isNaN(parseInt(fromX)) ? 0:fromX) + "," + (isNaN(parseInt(fromY)) ? 0:fromY);
line.to = (isNaN(parseInt(toX)) ? 0:toX) + "," + (isNaN(parseInt(toY)) ? 0:toY);
line.strokeweight=(isNaN(parseInt(weight)) ? 0:weight) + "pt";
line.fill=false;
line.filled=false;
line.getFrom=function(){
return line.from;
}
line.setFrom=function(x,y){
line.from=x + "," + y;
}
line.getTo=function(){
return line.to;
}
line.setTo=function(x,y){
line.to=x + "," + y;
}
return line;
}
window.onload = function () {
App.Start();
}
<js/util.js>
// 寻找对象的绝对X坐标
function findPosX(obj) {
var curleft = 0;
if (obj.offsetParent) {
while (obj.offsetParent) {
curleft += obj.offsetLeft;
obj = obj.offsetParent;
}
} else if (obj.x) curleft += obj.x;
return curleft;
}
// 寻找对象的绝对Y坐标
function findPosY(obj) {
var curtop = 0;
if (obj.offsetParent) {
while (obj.offsetParent) {
curtop += obj.offsetTop;
obj = obj.offsetParent;
}
} else if (obj.y) curtop += obj.y;
return curtop;
}