canvas实现画板功能,包括画笔颜色,粗细,圆滑曲线,橡皮擦,撤回上一步,清空画板,保存为图片

在这里插入图片描述
js部分:

 <script>
        let canvas = document.getElementById('can')
        let ctx = canvas.getContext('2d')
        
        // 先画一个和画布同样大小的矩形,在保存时可有背景颜色
        ctx.fillStyle="#fff";
        ctx.fillRect(0,0,canvas.width,canvas.height);
        let textColor = "#000" // 画笔初始颜色为黑色
        let imgs= []
        
        // 撤销按钮的样式状态
        let backFlag = false
        document.getElementById('back').style.background = '#999'
        
        let points = [];
        let beginPoint = null;
        
        // 画笔动作
        function pen(color){
            canvas.onmousedown = function (e){
                let x = e.pageX - canvas.offsetLeft
                let y = e.pageY - canvas.offsetTop
                points.push({x, y});
                beginPoint = {x, y};
                backFlag = true
                document.getElementById('back').style.background = '#ccc'
                
                document.onmousemove = function (e){
                    let x = e.pageX - canvas.offsetLeft
                    let y = e.pageY - canvas.offsetTop
                    ctx.strokeStyle = color
                    
                    // 使用贝塞尔曲线画出圆滑的曲线
                    points.push({x,y})
                    if (points.length > 3) {
                        const lastTwoPoints = points.slice(-2);
                        const controlPoint = lastTwoPoints[0];
                        const endPoint = {
                            x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2,
                            y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2,
                        }
                        drawLine(beginPoint, controlPoint, endPoint);
                        beginPoint = endPoint;
                    }
                }
                
                // 将每一个画笔动作存入imgs,用于撤销
                let obj = ctx.getImageData(0, 0, canvas.width, canvas.height)
                imgs.push(obj)
            }
            document.onmouseup = function () {
                ctx.closePath()
                document.onmousemove = null
            }
        }
        function drawLine(beginPoint, controlPoint, endPoint){
            ctx.beginPath();
            ctx.moveTo(beginPoint.x, beginPoint.y);
            ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
            ctx.stroke();
        }
        pen(textColor)
        // 改变画笔/橡皮擦粗细
        function changeWidth() {
            let w = document.getElementById('rangeValue').value = document.getElementById('rangeIpt').value
            ctx.lineWidth = w
        }
        // 清空画布
        function clearAll() {
            ctx.clearRect(0,0,canvas.width,canvas.height)
            // 清空画布后重新画一个和画布同样大小的矩形,在保存时可有背景颜色
            ctx.fillStyle="#fff";
            ctx.fillRect(0,0,canvas.width,canvas.height);
            document.getElementById('back').style.background = '#999'
            backFlag = false
        }
        // 橡皮擦,将画笔变成白色(背景颜色)
        function clearSome() {
            pen('#fff')
        }
        // 画笔颜色
        function draw(data) {
            pen(data)
        }
        // 撤销按钮,将存入的画笔动作数组删除最后一个,再重新绘制到画布上
        function back() {
            if(backFlag){
                let img = imgs.pop()
                ctx.putImageData(img,0,0);
                // 撤销按钮的样式
                if(imgs.length > 0){
                    document.getElementById('back').style.background = '#ccc'
                    backFlag = true
                }else{
                    document.getElementById('back').style.background = '#999'
                    backFlag = false
                }
            }
        }
        // 将画布存储为图片显示在页面
        function save() {
            document.getElementById('saveImg').src = canvas.toDataURL();
        }
    </script>

html部分

 <!--左侧按钮-->
 <div class="btns">
     <p style="color: #fff;font-size: 14px">画笔/橡皮擦粗细:</p>
     <input type="range" max="20" min="1" onchange="changeWidth()" value="1" id="rangeIpt">
     <input type="text" id="rangeValue" value="1">
     <p style="color: #fff;font-size: 14px">画笔颜色:</p>
     <div class="color-box">
         <div class="color-div" style="background: rgb(255,165,0)" onclick="draw('rgb(255,165,0)')"></div>
         <div class="color-div" style="background: #000" onclick="draw('#000')"></div>
         <div class="color-div" style="background: rgb(255,0,0)" onclick="draw('rgb(255,0,0)')"></div>
         <div class="color-div" style="background: rgb(0,128,0)" onclick="draw('rgb(0,128,0)')"></div>
     </div>
     <div class="btn" onclick="clearAll()">清空</div>
     <div class="btn" onclick="clearSome()">橡皮</div>
     <div class="btn" onclick="back()" id="back">撤销</div>
     <div class="btn" onclick="save()">保存</div>
 </div>
 <!--画布-->
 <canvas width="500px" height="500px" id="can"></canvas>
 <!-- 生成的图片-->
 <div class="img-bg">
     <img src="" alt="" id="saveImg">
 </div>

css部分:

 <style>
     body{
         background: #434343;
         display: flex;
         flex-direction: row;
     }
     #can{
         background: #fff;
     }
     .btns{
         display: flex;
         flex-direction: column;
         align-items: center;
     }
     #rangeValue{
         width: 60px;
     }
     .btn{
         width: 60px;
         height: 30px;
         background: #ccc;
         border-radius: 4px;
         text-align: center;
         line-height: 30px;
         margin: 20px;
     }
     .btn:hover,.color-box:hover,.color-ipt:hover{
         cursor: pointer;
     }
     #saveImg{
         width: 200px;
         height: 200px;
     }
     .img-bg{
         margin: 50px;
     }
     .color-box{
         display: flex;
         flex-direction: row;
         margin: 20px;
     }
     .color-div{
         width: 20px;
         height: 20px;
         margin-right: 10px;
         border: 1px solid #fff;
     }
 </style>
  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
html5 canvas填色画游戏代码是一款适合儿童玩的益智类填色游戏,通过选中色块,来给模型填充颜色。支持多种模型选择填色效果。 function extend(O1,O2){     for(var i in O2){         O1[i]=O2[i];     } } function each(arr,f){     for(var i = 0;i<arr.length;i ){         f.call(arr[i],i,arr[i]);     } } function dataInfo(Obj,x,y){     var c=document.createElement("canvas");     var txt= c.getContext("2d");     c.width=Obj.img.width;     c.height=Obj.img.height;     txt.drawImage(Obj.img,0,0);     var data=txt.getImageData(x-1,y-1,3,3);     var num=0;     for(var q=0;q<data.data.length;q =4){         num =data.data[q 3];     }     num=num/9;     return parseInt(num); } var HGAME=new Object(); HGAME.event=new Object();//事件对象 HGAME.event.clickBuffer=new Array();//缓存要添加事件的节点 click buffer HGAME.animate=function(Obj){     var defaultObj={         time:30,//动画间隔         frequency:-1,//动画次数 -1表示无限制         action:function(){},//动画每一帧的动作         lastAction:function(){}//最后一次动画执行完成触发函数     };     extend(defaultObj,Obj);     var oldTime=new Date();     var newTime=null;     this.time=defaultObj.time;     this.frequency=defaultObj.frequency;     this.action=defaultObj.action;     this.lastAction=defaultObj.lastAction;     this.stop=function(){         cancelAnimationFrame(this.INT_BUFFER);     };
好的,下面是一个简单的 Android 画板示例代码,包括涂鸦、改变颜色橡皮擦、调节画笔粗细、撤销上一步和保存图片功能: MainActivity.java: ```java public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final int REQUEST_PERMISSION_CODE = 1001; private static final int MAX_STEP = 10; private static final int DEFAULT_COLOR = Color.BLACK; private static final int DEFAULT_SIZE = 5; private SurfaceView mSurfaceView; private Button mColorButton; private Button mEraserButton; private SeekBar mSizeSeekBar; private Button mUndoButton; private Button mSaveButton; private Paint mPaint; private int mColor = DEFAULT_COLOR; private int mSize = DEFAULT_SIZE; private Bitmap mBitmap; private Canvas mCanvas; private Stack<Bitmap> mBitmapStack; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSurfaceView = findViewById(R.id.surface_view); mColorButton = findViewById(R.id.color_button); mEraserButton = findViewById(R.id.eraser_button); mSizeSeekBar = findViewById(R.id.size_seek_bar); mUndoButton = findViewById(R.id.undo_button); mSaveButton = findViewById(R.id.save_button); mColorButton.setOnClickListener(this); mEraserButton.setOnClickListener(this); mUndoButton.setOnClickListener(this); mSaveButton.setOnClickListener(this); mSizeSeekBar.setMax(100); mSizeSeekBar.setProgress(DEFAULT_SIZE); mSizeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { mSize = progress; } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); mPaint = new Paint(); mPaint.setColor(mColor); mPaint.setStrokeWidth(mSize); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeJoin(Paint.Join.ROUND); mBitmap = Bitmap.createBitmap(mSurfaceView.getWidth(), mSurfaceView.getHeight(), Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); mBitmapStack = new Stack<>(); mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { mCanvas.drawColor(Color.WHITE); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); mCanvas.setBitmap(mBitmap); } @Override public void surfaceDestroyed(SurfaceHolder holder) { mBitmap.recycle(); } }); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.color_button: showColorPickerDialog(); break; case R.id.eraser_button: mColor = Color.WHITE; mPaint.setColor(mColor); break; case R.id.undo_button: undo(); break; case R.id.save_button: saveImage(); break; } } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { mBitmapStack.push(Bitmap.createBitmap(mBitmap)); } if (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_DOWN) { float x = event.getX(); float y = event.getY(); mCanvas.drawPoint(x, y, mPaint); mSurfaceView.getHolder().unlockCanvasAndPost(mCanvas); } if (mBitmapStack.size() > MAX_STEP) { mBitmapStack.remove(0); } return true; } private void showColorPickerDialog() { ColorPickerDialogBuilder .with(this) .setTitle("Color Picker") .initialColor(mColor) .wheelType(ColorPickerView.WHEEL_TYPE.FLOWER) .density(12) .setPositiveButton("OK", new ColorPickerClickListener() { @Override public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) { mColor = selectedColor; mPaint.setColor(mColor); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }) .build() .show(); } private void undo() { if (!mBitmapStack.isEmpty()) { mBitmap = mBitmapStack.pop(); mCanvas.setBitmap(mBitmap); mSurfaceView.getHolder().unlockCanvasAndPost(mCanvas); } } private void saveImage() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_CODE); return; } } String fileName = "Drawing_" + System.currentTimeMillis() + ".png"; File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), fileName); try { FileOutputStream fos = new FileOutputStream(file); mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); Toast.makeText(this, "Image saved to " + file.getAbsolutePath(), Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "Failed to save image", Toast.LENGTH_SHORT).show(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case REQUEST_PERMISSION_CODE: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { saveImage(); } else { Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show(); } break; } } } ``` activity_main.xml: ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <SurfaceView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:id="@+id/tool_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" android:padding="16dp"> <Button android:id="@+id/color_button" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginEnd="16dp" android:backgroundTint="@color/black" android:textColor="@color/white" android:text="C" /> <Button android:id="@+id/eraser_button" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginEnd="16dp" android:backgroundTint="@color/white" android:textColor="@color/black" android:text="E" /> <SeekBar android:id="@+id/size_seek_bar" android:layout_width="0dp" android:layout_height="48dp" android:layout_marginEnd="16dp" android:layout_weight="1" /> <Button android:id="@+id/undo_button" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginEnd="16dp" android:backgroundTint="@color/black" android:textColor="@color/white" android:text="U" /> <Button android:id="@+id/save_button" android:layout_width="48dp" android:layout_height="48dp" android:backgroundTint="@color/black" android:textColor="@color/white" android:text="S" /> </LinearLayout> </RelativeLayout> ``` 这个示例代码中包含了涂鸦、改变颜色橡皮擦、调节画笔粗细、撤销上一步和保存图片功能,你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值