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>