当前位置: 首页 > Web前端 > HTML5

可扩展的面向对象的画布绘制程序

时间:2023-04-05 22:13:20 HTML5

面向对象的画布绘制程序项目介绍整个项目分为两部分待绘制ElementDemo演示地址Demo是最新的代码项目扩展性强spritesprite实现父类Element{constructor(options={fillStyle:'rgba(0,0,0,0)',lineWidth:1,strokeStyle:'rgba(0,0,0,255)'}){this.options=options}setStyle(options){this.options=Object.assign(this.options.options)}}属性:选项存储所有绘图属性fillStyle:设置或返回用于填充绘画的颜色、渐变或模式strokeStyle:设置或返回用于笔触的颜色、渐变或模式lineWidth:使用getContext("2d")对象的本机属性设置或返回当前线宽,只有这些这里列出三个属性,如果需要可以扩展。如果需要,可以继续扩展该方法:setStyle方法用于重新设置当前精灵的属性。如果需要,您可以继续扩展。所有的精灵都继承了Element类。子类子类是每个精灵元素的具体实现。这里介绍Circle元素的实现classCircleextendsElement{//锚点坐标(这里是圆心),半径,配置对象constructor(x,y,r=0,options){//调用父类构造函数super(options)this.x=xthis.y=ythis.r=r}//改变元素大小resize(x,y){this.r=Math.sqrt((this.x-x)**2+(this.y-y)**2)}//将元素移动到新位置,接收两个参数,新元素位置moveTo(x,y){this.x=xthis.y=y}//判断点是否在元素中,接收两个参数,点的坐标choose(x,y){return((x-this.x)**2+(y-this.y)**2)<(this.r**2)}//偏移量,计算点与元素定位点的相对偏移量(ofsetX,offsetY)getOffset(x,y){return{x:x-this.x,y:y-this.y}}//绘制元素的实现,接收一个ctx对象,在指定画布上绘制当前元素draw(ctx){//获取需要的属性drawinglet{fillStyle,strokeStyle,lineWidth}=this.options//开始绘制beginPath()方法开始一个路径,或者重置当前路径ctx.beginPath()//设置属性ctx.fillStyle=fillStylectx.strokeStyle=strokeStylectx.lineWidth=lineWidth//画一个圆ctx.arc(this.x,this.y,this.r,0,2*Math.PI)//填充颜色ctx.stroke()ctx.fill()//绘制完成}//校验函数,判断当前元素是否满足指定条件,这里用来检查元素是否添加到场景validate(){returnthis.r>=3}}arc()方法创建弧/曲线(用于创建圆或圆的一部分)x圆心的x坐标。y圆心的y坐标。r圆的半径。sAngle起始角度,以弧度表示。(圆弧的圆形三点钟位置为0度)。eAngle以弧度表示的结束角度。逆时针可选。指定绘图是逆时针还是顺时针。假=顺时针,真=逆时针。注意:构造函数只需要两个形参,就是锚点的坐标。所有其他形式参数必须具有默认值。各方法的调用时机我们在canvas上绘制元素时回调resize方法。移动元素时调用moveTo方法。choose会在按下鼠标时调用,判断当前元素是否被选中。选择元素时调用getOffset以确定所选位置。draw绘图函数,在绘制元素到场景时调用。场景实现属性介绍classSence{constructor(id,options={width:600,height:400}){//Canvas属性this.canvas=document.querySelector('#'+id)this.canvas.width=options.widththis.canvas.height=options.heightthis.width=options.widththis.height=options.height//绘图对象this.ctx=this.canvas.getContext('2d')//off-屏幕画布this.outCanvas=document.createElement('canvas')this.outCanvas.width=this.widththis.outCanvas.height=this.heightthis.outCtx=this.outCanvas.getContext('2d')//画布状态这。stateList={drawing:'drawing',moving:'moving'}this.state=this.stateList.drawing//鼠标状态this.mouseState={//记录鼠标按下时的偏移量offsetX:0,offsetY:0,down:false,//记录鼠标当前状态是否按下target:null//当前操作的目标元素}//当前选中的精灵构造函数this.currentSpriteConstructor=null//存储精灵letsprites=[]这。sprites=sprites/*....*/}}事件逻辑类Sence{constructor(id,options={width:600,height:400}){/*...*///监听事件this.canvas.addEventListener('contextmenu',(e)=>{console.log(e)})//鼠标按下时的处理逻辑this.canvas.addEventListener('mousedown',(e)=>{//鼠标事件只有在按下左键时才会被处理if(e.button===0){//鼠标的位置letx=e.offsetXlety=e.offsetY//记录鼠标是否按下this.mouseState.down=true//创建一个临时目标//记录下targetelementlettarget=nullif(this.state===this.stateList.drawing){//判断当前是否有精灵构造函数,并构造对应的精灵元素if(this.currentSpriteConstructor){target=newthis.currentSpriteConstructor(x,y)}}elseif(this.state===this.stateList.movi??ng){letsprites=this.sprites//遍历所有精灵,调用它们的choose方法,判断是否被选中为(leti=精灵.length-1;我>=0;i--){如果(sprites[i].choose(x,y)){target=sprites[我打破;}}//如果选中,则调用目标的getOffset方法获取偏移量.y}}//保存当前目标元素this.mouseState.target=target//保存离屏画布中除目标元素外的所有元素letctx=this.outCtx//清空离屏画布ctx.clearRect(0,0,this.width,this.height)//将目标元素之外的所有元素绘制到离屏画布上this.sprites.forEach(item=>{if(item!==target){item.draw(ctx)}})if(target){//开始动画this.anmite()}}})this.canvas.addEventListener('mousemove',(e)=>{//如果鼠标按下并且有一个目标元素,下面的代码被执行if(this.mouseState.down&&this.mouseState.target){t.drawing){//调用当前目标的resize方法改变大小this.mouseState.target.resize(x,y)}elseif(this.state===this.stateList.movi??ng){//获取到存储中的偏移量。身体。addEventListener('mouseup',(e)=>{if(this.mouseState.down){//将鼠标按下状态记录为falsethis.mouseState.down=falseif(this.state===this.stateList.drawing){//调用目标的验证方法判断他是否应该被添加到场景中){//什么都不做}}})}}方法介绍classSence{//animationanmite(){requestAnimationFrame(()=>{//清除画布this.clear()//绘制离屏画布Go到当前画布this.paint(this.outCanvas)//绘制目标this.mouseState.target.draw(this.ctx)//如果鼠标按下继续执行下一帧动画if(this.mouseState.down){this.anmite()}})}//手动创建的精灵可以添加到画布中append(sprite){this.sprites.push(sprite)sprite.draw(this.ctx)}//根据ID值,从场景中删除相应的元素remove(id){this.sprites.splice(id,1)}//clearRect清除指定区域的canvas内容clear(){this.ctx.clearRect(0,0,this.width,this.height)}//重绘整个画布的内容reset(){this.clear()this.sprites.forEach(element=>{element.draw(this.ctx)})}//将离屏画布绘制到页面的画布canvaspaint(canvas,x=0,y=0){this.ctx.drawImage(canvas,x,y,this.width,this.height)}//设置当前选中的精灵构造函数setCurrentSprite(Element){this.currentSpriteConstructor=Element}}Demo演示地址