HTML5 canvas 在线画笔绘图工具(二)



Canvas+Javascript 带图标的工具条制作 TToolbar


工具条是由一个TToolbar对象和两个按钮对象(TImageButton、TColorButton)组成,因为之前我大部分时间是使用d.e.l.p.h.i进行开发,所以命名方面比较偏向于d.e.l.p.h.i的风格,请处女座的同学忍耐将就一下。


图标按钮 TImageButton


TImageButton 是一个图标按钮对象,可以设置三个图标文件,分别是正常状态,鼠标移上状态,鼠标点击状态。


下面我们介绍一下TImageButton的参数:

 

Command是按钮对应的功能编号,比如我们定义1为直线,2为矩形.

NormalSrc, MouseOnSrc, MouseDownSrc 分别为正常状态,鼠标移上状态,鼠标点击状态 的图标地址。

x, y, width, height 按钮在工具条上的位置和尺寸。

Toolbar 为宿主工具条。

Group 是按钮所属分组。

function TImageButton(Command,
                      NormalSrc,
                      MouseOnSrc,
                      MouseDownSrc,
                      x,
                      y,
                      width,
                      height,
                      Toolbar,
                      group)
{
}


下面为在Canvas上绘制按钮图标的代码

当鼠标移进按钮或鼠标移出按钮时,将调用ChangeState来改变按钮的状态.为按钮设置不同的图标属性,然后通过Clear()函数将原来的图素清除,再利用RenderImage函数绘制新的按钮。


	function Clear() {
		Context.clearRect(Toolbar.x + x, Toolbar.y + y, width, height);
	}

	function LoadImage(newsrc) {

		image.src = newsrc;

		if (image.complete) {
			RenderImage(image);
		} else
			image.onload = function() {
				RenderImage(image);
			};
	}

	function RenderImage(image) {

		Context.drawImage(image, Toolbar.x + x, Toolbar.y + y, width, height);
	}

	function ChangeState(NewState) {

		state = NewState;
		Clear();
		if (NewState == CSN)
			LoadImage(NormalSrc);
		else if (NewState == CSO)
			LoadImage(MouseOnSrc);
		else if (NewState == CSD)
			LoadImage(MouseDownSrc);
	}


PointIn函数用于检测鼠标所在位置是否在当前按钮所覆盖区域中。

注意这里的AbsX与AbsY函数,由于鼠标的x值和y值是鼠标在页面中的坐标,而当前TImageButton对象的x,y是其在TToolbar对象中的坐标位置。因此我们在计算该TImageButton所覆盖区域时,应当加上画布在页中的坐标以及TToolbar对象在画布中的偏移量。



</pre><pre class="javascript" name="code">    function PointIn (testx,testy)
    {
       if ((testx>Absx())&&(testx<(Absx()+width))
          &&(testy>Absy()) && (testy<(Absy()+height)))
         {
   
              return true;
              
              }
          else
             return false; 
              
    }; 

function Absx() {
		return Canvas.offsetLeft + Toolbar.x + x;
	};
function Absy() {

		return Canvas.offsetTop + Toolbar.y + y;
	};


颜色选择按钮TColorButton

从下面TColorButton对象的建立参数我们可以看到,它与TImageButton基本类似,按照面向对象的法则,应当抽取一个基类,由两个TColorButton和TImageButton来继承。但我还没有学会如何在Javascript中实现对类的继承,所以暂时将它们分成两个完全不相干的类。

注意一下这个建立函数与TImageButton的唯一区别是它的Command参数不再是保存命令的编号,而是保存颜色的值。


function TColorButton(Command,
                      x,
                      y,
                      width,
                      height,
                      Toolbar,
                      group)
{
</pre><pre class="javascript" name="code">}


我们再来看看它的按钮是如何绘制到画布上的

TColorButton同样有 mousemoveon,mouseleave,click三种状态。当鼠标在按钮上时在颜色选择小框外画一个淡黄色的小框。


function Clear()
    {
       Context.clearRect(Toolbar.x+ x,Toolbar.y+ y,width,height);
    }
    function RenderButton()
    {
       
       Context.fillStyle=command;
       Context.fillRect(Toolbar.x+ x, Toolbar.y+ y,width,height);
       if (state==CSO)
       {
       	  Context.strokeStyle="#FFCC33";
		  Context.lineWidth=2;
		  Context.strokeRect(Toolbar.x+ x+2, Toolbar.y+ y+2,width-4,height-4); 
       }
    }
    function ChangeState(NewState)
    {
       
       state=NewState;
       Clear();
       RenderButton();  
    }




主工具条TToolbar

function TToolbar(Canvas, x, y, width, height) {
	var Context = Canvas.getContext('2d');
	this.Canvas = Canvas;
	this.x = x;
	this.y = y;
	this.width = width;
	this.height = height;
	var CurrentShapeProperty;
	var BorderColor;
	btnList = new Array();
	btnCounter = 0;
	Create();
}

首先我们来看一下TToolbar的建立参数和成员变量

Canvas是工具条的图象载体,与用户交互的UI元素. x,y 为工具条在画布(Canvas) 上的偏移量,width,height分别为工具条的宽度和高度.

定义画布的上下文

var Context = Canvas.getContext('2d');

CurrentShapeProperty 用于记录选择的一些图形属性 如画笔的宽度,颜色等.


TToolbar负责做两件重要的工作

1.判断鼠标移动到了哪个按钮或者鼠标点击了哪个按钮.

利用 InstallEvents 绑定工具条的画布Canvas鼠标事件.

mousemove函数逐个判断当前工具条所管理的按钮是否获得了鼠标焦点. 如果当前鼠标移到了该按钮上,将该按钮的图标设为相应图标(在testHit函数中).其余图标设置为普通状态.

mousedown 函数逐个判断当前工具条所管理的按钮是否获得了鼠标点击.如果是颜色按钮则将当前选中的颜色值拷贝到大颜色按钮.

	mousemove = function(event) {
		var Current = null;
		for (var i = 0; i < btnList.length; i++) {
			if (btnList[i].testHit(event.clientX, event.clientY) == true)
				Current = btnList[i];
		}
		if (Current != null) {
			for (var i = 0; i < btnList.length; i++) {
					if ((btnList[i] != Current) && (btnList[i].getisChecked() == false))
						btnList[i].setNormal();
			}
		}
	};
	mousedown = function(evnet) {
		var Current = null;
		for (var i = 0; i < btnList.length; i++) {

			if (btnList[i].testMouseDown(event.clientX, event.clientY) == true)
				Current = btnList[i];
		}
		if (Current != null) {
			for (var i = 0; i < btnList.length; i++) {
				if (Current.getGroup() == btnList[i].getGroup()) {
					if (btnList[i] != Current)
						btnList[i].setNormal();
				}
			}
			if (Current.getGroup()==3)
			{
			  var Color=Current.Command();
			  ColorSelected(Color);
			 }
		}
		
	};

	//安装鼠标移动、点击等方法
	this.InstallEvents = function() {
		Canvas.onmousemove = function(event) {
			mousemove(event);
		};
		Canvas.onmousedown = function(event) {
			mousedown(event);
		};
	};


另外我之前想用以下方法来绑定鼠标事件,没有成功请帮看一下问题出在哪里,谢谢

	function AddEvent(element, eventName, eventHandler) {
		window.alert( typeof element.addEventListener);
		if ( typeof element.addEventListener != "undefined") {
			window.alert(eventHandler);
			element.addEventListener(eventName, eventHandler, false);
			window.alert(element.onmousemove);
		} else
			element.attachEvent(eventName, eventHandler);
	}

	
	//安装鼠标移动、点击等方法
	this.InstallEvents = function() {
		AddEvent(Canvas,"onmousemove",this.mousemove);
		AddEvent(Canvas,"onmousedown",this.mousedown);
	};



2.管理画图的命令(TComand)

建立绘图命令会在后续的章节进行介绍.

 

this.getNewCommand = function(DisplayCanvas) {
		for (var i = 0; i < btnList.length; i++) {
			if (btnList[i].getGroup() == 1) {
				if (btnList[i].getisChecked()) {
					var commandId = btnList[i].Command();
					var command = new TCommand(DisplayCanvas, commandId);
					return command;
				}
			}

		}
		return null;
	};

在线演示


工具条对象完整代码(TToolbar)

function TToolbar(Canvas, x, y, width, height) {
	var Context = Canvas.getContext('2d');
	this.Canvas = Canvas;
	this.x = x;
	this.y = y;
	this.width = width;
	this.height = height;
	var CurrentShapeProperty;
	var BorderColor;
	btnList = new Array();
	btnCounter = 0;
	Create();
	// InstallEvents();
	function Create() {

		Context.strokeStyle = "black";
		Context.lineWidth = "2";
		Context.strokeRect(x, y, width, height);
	}


	this.AddButton = function(button) {
		btnList[btnCounter++] = button;
	};
	function AddEvent(element, eventName, eventHandler) {
		window.alert( typeof element.addEventListener);
		if ( typeof element.addEventListener != "undefined") {
			window.alert(eventHandler);
			element.addEventListener(eventName, eventHandler, false);
			window.alert(element.onmousemove);
		} else
			element.attachEvent(eventName, eventHandler);
	}

	mousemove = function(event) {
		var Current = null;
		for (var i = 0; i < btnList.length; i++) {
			if (btnList[i].testHit(event.clientX, event.clientY) == true)
				Current = btnList[i];
		}
		if (Current != null) {
			for (var i = 0; i < btnList.length; i++) {
					if ((btnList[i] != Current) && (btnList[i].getisChecked() == false))
						btnList[i].setNormal();
			}
		}
	};
	mousedown = function(evnet) {
		var Current = null;
		for (var i = 0; i < btnList.length; i++) {

			if (btnList[i].testMouseDown(event.clientX, event.clientY) == true)
				Current = btnList[i];
		}
		if (Current != null) {
			for (var i = 0; i < btnList.length; i++) {
				if (Current.getGroup() == btnList[i].getGroup()) {
					if (btnList[i] != Current)
						btnList[i].setNormal();
				}
			}
			if (Current.getGroup()==3)
			{
			  var Color=Current.Command();
			  ColorSelected(Color);
			 }
		}
		
	};

	//安装鼠标移动、点击等方法
	this.InstallEvents = function() {
		//AddEvent(Canvas,"onmousemove",this.mousemove);
		//AddEvent(Canvas,"onmousedown",this.mousedown);
		//Canvas.οnmοusemοve=this.mousemove;
		Canvas.onmousemove = function(event) {
			mousemove(event);
		};
		Canvas.onmousedown = function(event) {
			mousedown(event);
		};
	};
	this.setBorderColorButton=function(ColorButton)
	{
		BorderColor=ColorButton;		
	};
	function ColorSelected (color) {
	   BorderColor.setColor(color);
	} 
	this.getNewCommand = function(DisplayCanvas) {
		for (var i = 0; i < btnList.length; i++) {
			if (btnList[i].getGroup() == 1) {
				if (btnList[i].getisChecked()) {
					var commandId = btnList[i].Command();
					var command = new TCommand(DisplayCanvas, commandId);
					return command;
				}
			}

		}
		return null;
	};
	this.getShapeProperty = function() {
		if (typeof CurrentShapeProperty=="undefined")
		CurrentShapeProperty = new TShapeProperty();
		CurrentShapeProperty.setLineColor(BorderColor.Command());
		for (var i = 0; i < btnList.length; i++) {
			if (btnList[i].getGroup() == 2) {
				if (btnList[i].getisChecked()) {
					CurrentShapeProperty.setLineWidth(btnList[i].Command()); 
				}
			}
		}
		return CurrentShapeProperty;
	};
	
}

图片按钮完整代码(TImageButton)

 

function TImageButton(Command, NormalSrc, MouseOnSrc, MouseDownSrc, x, y, width, height, Toolbar, group) {
	var command = Command;
	var NormalSrc = NormalSrc;
	var MouseOnSrc = MouseOnSrc;
	var MouseDownSrc = MouseDownSrc;
	var x = x;
	var y = y;
	var width = width;
	var height = height;
	var Canvas = Toolbar.Canvas;
	var Context = Canvas.getContext("2d");
	var CSN = "Normal";
	var CSO = "MouseOn";
	var CSD = "MouseDown";
	var state = CSN;
	var Group = group;
	var image = new Image();
	CreateButton();

	function CreateButton() {

		LoadImage(NormalSrc);
	}

	function Absx() {
		return Canvas.offsetLeft + Toolbar.x + x;
	};
	function Absy() {

		return Canvas.offsetTop + Toolbar.y + y;
	};
	function PointIn(testx, testy) {
		if ((testx > Absx()) && (testx < (Absx() + width)) && (testy > Absy()) && (testy < (Absy() + height))) {

			return true;

		} else
			return false;

	};
	function Clear() {
		Context.clearRect(Toolbar.x + x, Toolbar.y + y, width, height);
	}

	function LoadImage(newsrc) {

		image.src = newsrc;

		if (image.complete) {
			RenderImage(image);
		} else
			image.onload = function() {
				RenderImage(image);
			};
	}

	function RenderImage(image) {

		Context.drawImage(image, Toolbar.x + x, Toolbar.y + y, width, height);
	}

	function ChangeState(NewState) {

		state = NewState;
		Clear();
		if (NewState == CSN)
			LoadImage(NormalSrc);
		else if (NewState == CSO)
			LoadImage(MouseOnSrc);
		else if (NewState == CSD)
			LoadImage(MouseDownSrc);
	}


	this.testHit = function(dx, dy) {

		if (PointIn(dx, dy)) {

			if (state == CSN) {
				ChangeState(CSO);

			}
			return true;
		}
		return false;

	};
	this.OnClick = function() {
	};
	this.testMouseDown = function(dx, dy) {

		if (PointIn(dx, dy)) {
			ChangeState(CSD);
			this.OnClick();
			return true;
		}
		return false;
	};
	this.getisChecked = function() {
		return (state == CSD);
	};
	this.Command = function() {
		return command;
	};
	this.MoveOn = function() {
		return (state == CSO);
	};
	this.setNormal = function() {
		ChangeState(CSN);
	};
	this.getGroup = function() {
		return Group;
	};
}


颜色选择框的完整代码(TColorButton)

<span style="font-size:12px;">function TColorButton(Command,
                      x,
                      y,
                      width,
                      height,
                      Toolbar,
                      group)
{
	var command=Command;
    var x=x;
    var y=y;
    var width=width;
    var height=height;
    var Canvas=Toolbar.Canvas;
    var Context=Canvas.getContext("2d");
    var CSN="Normal";
    var CSO="MouseOn";
    var CSD="MouseDown";
    var state=CSN;
    var Group=group;
    CreateButton();
    function CreateButton()
    {
       RenderButton();
    }
    function Absx() 
    {
       return Canvas.offsetLeft+Toolbar.x+x;
    };
    function Absy() 
    {
       
       return Canvas.offsetTop+Toolbar.y+y;
    };
    function PointIn (testx,testy)
    {
       if ((testx>Absx())&&(testx<(Absx()+width))
          &&(testy>Absy()) && (testy<(Absy()+height)))
         {
   
              return true;
              
              }
          else
             return false; 
              
    }; 
    function Clear()
    {
       Context.clearRect(Toolbar.x+ x,Toolbar.y+ y,width,height);
    }
    function RenderButton()
    {
       
       Context.fillStyle=command;
       Context.fillRect(Toolbar.x+ x, Toolbar.y+ y,width,height);
       if (state==CSO)
       {
       	  Context.strokeStyle="#FFCC33";
		  Context.lineWidth=2;
		  Context.strokeRect(Toolbar.x+ x+2, Toolbar.y+ y+2,width-4,height-4); 
       }
    }
    function ChangeState(NewState)
    {
       
       state=NewState;
       Clear();
       RenderButton();  
    }
    this.testHit=function(dx,dy)
    {
      
       if (PointIn(dx,dy))
       {
 
         if (state==CSN)
         {
            ChangeState(CSO);

         }
         return true;
       }
       return false;

    };
    this.testMouseDown=function(dx,dy)
    {
      
       if (PointIn(dx,dy))
       {
            ChangeState(CSD);
            return true;
       } 
       return false;
    };
    this.getisChecked=function()
    {
       return (state==CSD);
    };
    this.Command=function()
    {
       return command;
    };
    this.MoveOn=function()
    {
      return (state==CSO);
    };
    this.setNormal=function()
    {
       ChangeState(CSN);
    };
    this.getGroup=function()
    {
        return Group;
    };
    this.setColor=function(color)
    {
    	command=color;
    	Context.fillStyle=command;
        Context.fillRect(Toolbar.x+ x, Toolbar.y+ y,width,height);
    };
	
} 
</span>






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值