用Wpf做一个画笔画板(续5-Diagram画板)

Posted WPF学习分享

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用Wpf做一个画笔画板(续5-Diagram画板)相关的知识,希望对你有一定的参考价值。

先上效果图吧

同样老规矩,先上源码地址:https://gitee.com/akwkevin/aistudio.-wpf.-diagram

本次实现的内容有

    • [1] 画笔实现
    • [2] 封闭画笔实现
    • [3] 钢笔实现
    • [4] 文字画笔
    • [5] 直线,矩形,椭圆
    • [6] Path形状
    • [7] 取色器
    • [8] 三种画笔可选

画笔示例入口

 

 示例截图

 核心代码:

1.Ellipse的实现:Geometry = new EllipseGeometry(new Rect(Points[0], Points[1]));

2.Rectangle的实现:   Geometry = new RectangleGeometry(new Rect(Points[0], Points[1]));

3.Line的实现:  Geometry = new LineGeometry(Points[0], Points[1]);

4.文本的实现:

var formattedText = new FormattedText(Text,
System.Globalization.CultureInfo.InvariantCulture,
FlowDirection.LeftToRight,
typeface,
FontViewModel.FontSize,
new SolidColorBrush(FontViewModel.FontColor));

Geometry = formattedText.BuildGeometry(new Point()).GetFlattenedPathGeometry();

5.多点连接线 

var geometry = new PathGeometry();
var figure = new PathFigure StartPoint = Points[0] ;
geometry.Figures.Add(figure);

for (int i = 1; i < Points.Count; i++)

LineSegment arc = new LineSegment(Points[i], true);
geometry.Figures[0].Segments.Add(arc);

Geometry = geometry;

6.Path形状

var path = GetPath();
PathGeometry pathGeometry = PathGeometry.CreateFromGeometry(Geometry.Parse(path));
var transformGroup = new TransformGroup();
double radiox = Math.Abs(Points[1].X - Points[0].X) / pathGeometry.Bounds.Width;
double radioy = Math.Abs(Points[1].Y - Points[0].Y) / pathGeometry.Bounds.Height;
transformGroup.Children.Add(new TranslateTransform((Points[0].X) / radiox - pathGeometry.Bounds.Left, (Points[0].Y) / radioy - pathGeometry.Bounds.Top));
transformGroup.Children.Add(new ScaleTransform(radiox, radioy));
pathGeometry.Transform = transformGroup;
Geometry = pathGeometry;

7.橡皮的实现

erase.Transform = new TranslateTransform(0 - Left, 0 - Top);

Geometry = Geometry.Combine(Geometry, erase, GeometryCombineMode.Exclude, null);

8.取色器的实现

var point = CursorPointManager.GetCursorPosition();
Root.CurrentColor = ColorPickerManager.GetColor(point.X, point.Y);

讲一个关键点:形状要可擦除,必须要转换一下

Geometry = Geometry.GetWidenedPathGeometry(aPen); 

今天实在有点懒得搞,就这样吧。

 

Day08 - HTML5 Canvas 实现彩虹画笔绘画板指南

项目效果

Day08 - HTML5 Canvas 实现彩虹画笔绘画板指南

用 HTML5 中的 Canvas 的路径绘制实现一个绘画板,可供鼠标画画,颜色呈彩虹色渐变,画笔大小同样呈渐变效果。这部分不涉及 CSS 内容,全部由 JS 来实现。

涉及特性

Canvas:

  • 模板骨架

  • 基本属性

    • getContext()

    • strokeStyle

    • fillStyle

    • fillRect

    • lineCap

    • lineJoin

  • 路径绘制

    • beginPath()

    • lineTo()

    • moveTo()

鼠标事件处理:

  • mousemove

  • mousedown

  • mouseup

  • mouseout

过程指南

  1. 获取 HTML 中的 <canvas> 元素,并设定宽度和高度

  2. .getContext('2d') 获取上下文,下面以 ctx 表示

  3. 设定 ctx 基本属性

    • 描边和线条颜色

    • 线条宽度

    • 线条末端形状

  4. 绘画效果

    1. 设定一个用于标记绘画状态的变量

    2. 鼠标事件监听,不同类型的事件将标记变量设为不同值

    3. 编写发生绘制时触发的函数,设定绘制路径起点、终点

  5. 线条彩虹渐变效果(运用 hsl 的 h 值的变化,累加)

  6. 线条粗细渐变效果(设定一个范围,当超出这个范围时,线条粗细进行逆向改变

Canvas相关知识

Canvas_API

HELLOWORLD简单介绍

一、 模板骨架

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <title>HTML5 Canvas 实现彩虹画笔绘画板</title>  <script type="text/javascript">    function draw() {      var canvas = document.getElementById('tutorial');      if (canvas.getContext) {        var ctx = canvas.getContext('2d');      }    }  </script>  <style type="text/css">    canvas {      border: 1px solid black;    }  </style></head><body>  <canvas id="tutorial" width="150" height="150"></canvas></body></html>
  • canvas> 元素

<canvas id="tutorial" width="150" height="150"></canvas>

canvas 看起来和 img 元素很相像,唯一的不同就是它并没有 src 和alt 属性。实际上,canvas 标签只有两个属性——widthheight。这些都是可选的,并且同样利用 DOM properties 来设置。当没有设置宽度和高度的时候,canvas会初始化宽度为300像素和高度为150像素。该元素可以使用CSS来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果CSS的尺寸与初始画布的比例不一致,它会出现扭曲。

  • 渲染上下文(The rendering context)

var canvas = document.getElementById('tutorial');var ctx = canvas.getContext('2d');

canvas元素创造了一个固定大小的画布,它公开了一个或多个渲染上下文,其可以用来绘制和处理要展示的内容。

canvas起初是空白的。为了展示,首先脚本需要找到渲染上下文,然后在它的上面绘制。canvas元素有一个叫做 getContext() 的方法,这个方法是用来获得渲染上下文和它的绘画功能。getContext()只有一个参数,上下文的格式。对于2D图像而言,基本教程,你可以使用CanvasRenderingContext2D

  • 检查支持性

替换内容是用于在不支持 canvas 标签的浏览器中展示的。通过简单的测试getContext()方法的存在,脚本可以检查编程支持性。

var canvas = document.getElementById('tutorial');if (canvas.getContext){    //支持
  var ctx = canvas.getContext('2d');  // drawing code here} else {   //不支持
  // canvas-unsupported code here}

二、一个简单例子

一开始,让我们来看个简单的例子,我们绘制了两个有趣的长方形,其中的一个有着alpha透明度。我们将在接下来的例子里深入探索一下这是如何工作的。

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <title>HTML5 Canvas 实现彩虹画笔绘画板</title>  <script type="text/javascript">    function draw() {      var canvas = document.getElementById('tutorial');      if (canvas.getContext) {        var ctx = canvas.getContext('2d');        ctx.fillStyle = "rgb(200,0,0)";        ctx.fillRect (10, 10, 55, 50);        ctx.fillStyle = "rgba(0, 0, 200, 0.5)";        ctx.fillRect (30, 30, 55, 50);      }    }  </script>  <style type="text/css">    canvas {      border: 1px solid black;    }  </style></head><body onload="draw();">  <canvas id="tutorial" width="300" height="300"></canvas></body></html>

效果图:


项目源码分析

源码

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <title>HTML5 Canvas</title>  <style>    html,    body {      margin: 0;      overflow: hidden;    }    canvas {      overflow: hidden;    }  </style></head><body>  <canvas id="draw" width="800" height="800" style="overflow:auto;"></canvas>  <script>    // 1.获取canvas节点    const canvas = document.querySelector('#draw');    if (canvas.getContext) {      //支持      var ctx = canvas.getContext('2d');      // drawing code here    } else {      //不支持      // canvas-unsupported code here      console.log("canvas-unsupported code here");    }        canvas.width = window.innerWidth;    canvas.height = window.innerHeight;    let isDrawing = false;    let lastX = 0;    let lastY = 0;    ctx.lineWidth = 90;    ctx.lineCap = "round";    ctx.lineJoin = "round";    ctx.strokeStyle = "#f00";    ctx.fillStyle = "#f00";    let hue = 0;    let direction = true;    let x = 0;    let y = 0;    function draw(e) {      if (!isDrawing) return;      x = e.offsetX;      y = e.offsetY;      // 彩虹效      ctx.strokeStyle = `hsl(${ hue }, 90%, 50%)`;      if (hue >= 360) hue = 0;      hue++;      // 控制笔触大小      if (ctx.lineWidth > 120 || ctx.lineWidth < 10) {        direction = !direction;      }      if (direction) {        ctx.lineWidth++;      } else {        ctx.lineWidth--;      }      // 控制绘制路径      ctx.beginPath();      ctx.moveTo(lastX, lastY);      ctx.lineTo(x, y);      ctx.stroke();      [lastX, lastY] = [x, y];    }    canvas.addEventListener('mousedown', (e) => {      isDrawing = true;      [lastX, lastY] = [e.offsetX, e.offsetY];    });    canvas.addEventListener('mousemove', draw);    canvas.addEventListener('mouseup', () => isDrawing = false);    canvas.addEventListener('mouseout', () => isDrawing = false);  </script></body></html>

源码分析

Canvas

canvas宽高设置

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

属性

  • lineCap:笔触的形状,有 round | butt | square 圆、平、方三种。

  • lineJoin:线条相交的样式,有 round | bevel | miter 圆交、斜交、斜接三种。

  • lineWidth:线条的宽度

  • strokeStyle:线条描边的颜色

  • fillStyle:填充的颜色

方法

  • beginPath():新建一条路径

  • stroke():绘制轮廓

  • moveTo():(此次)绘制操作的起点

  • lineTo():路径的终点

彩虹渐变颜色——HSL

在这个挑战中,涉及到改变线条的颜色,如何实现彩虹的渐变效果?我们需要利用 HSL 色彩模式,首先可以去这个网站 http://mothereffinghsl.com 感受一下 HSL 不同色彩值对应的效果。

  • H(hue) 代表色调,取值为 0~360,专业术语叫色相

  • S 是饱和度,可以理解为掺杂进去的灰度值,取值为 0~1

  • L 则是亮度,取值也是 0~1,或者百分比。

这之中 H 值从 0 到 360 的变化代表了色相的角度的值域变化,利用这一点就可以实现绘制时线条颜色的渐变了,只需要在它的值超过 360 时恢复到 0 重新累加即可。

let hue = 0;

ctx.strokeStyle = `hsl(${ hue }, 100%, 50%)`;	
if(hue >= 360) hue = 0;
hue++;

除此之外,如果想实现黑白水墨的颜色,可以将颜色设置为黑色,通过透明度的改变来实现深浅不一的颜色。

控制笔触大小

 // 控制笔触大小
 if (ctx.lineWidth > 120 || ctx.lineWidth < 10) {
   direction = !direction;
 } if (direction) {
   ctx.lineWidth++;
 } else {
   ctx.lineWidth--;
 }

上面的代码中,根据线条的宽度的变化来控制direction的值,根据direction的值来控制线宽是增加还是减少。

控制线条路径

 // 控制绘制路径
 ctx.beginPath();

 ctx.moveTo(lastX, lastY);
 ctx.lineTo(x, y);
 ctx.stroke();// 坐标重置
 [lastX, lastY] = [x, y];

事件监听代码逻辑分析

canvas.addEventListener('mousedown', (e) => {<!--开始绘图--> isDrawing = true; <!--绘图起始坐标初始化--> [lastX, lastY] = [e.offsetX, e.offsetY]; });<!--鼠标移动时,调用draw方法-->canvas.addEventListener('mousemove', draw);<!--鼠标抬起时,将isDrawing置为false-->canvas.addEventListener('mouseup', () => isDrawing = false);<!--当鼠标不在可绘图区域范围内时,将isDrawing置为fals-->canvas.addEventListener('mouseout', () => isDrawing = false);

源码下载

Github Source Code

社群品牌:从零到壹全栈部落

定位:寻找共好,共同学习,持续输出全栈技术社群

业界荣誉:IT界的逻辑思维

文化:输出是最好的学习方式

社群发起人:春哥(从零到壹创始人,交流微信:liyc1215)

技术交流社区:全栈部落BBS

全栈部落完整系列教程:全栈部落完整电子书学习笔记

关注全栈部落官方公众号,每晚十点接收系列原创技术推送
Day08 - HTML5 Canvas 实现彩虹画笔绘画板指南

扫描二维码

申请加入全栈部落

以上是关于用Wpf做一个画笔画板(续5-Diagram画板)的主要内容,如果未能解决你的问题,请参考以下文章

用Wpf做一个思维导图(续3-Diagram画板)

使用Canvas和JavaScript做一个画板

Day08 - HTML5 Canvas 实现彩虹画笔绘画板指南

canvas小创作 之 实现一个画板(功能:画笔颜色粗细可以任选;橡皮擦功能和清空画板功能)

canvas画板绘图 矩形 圆形 椭圆 自定义多边形 画笔/铅笔 曲线 橡皮擦

#夏日挑战赛# HarmonyOS 实现一个绘画板