AxeSlide软件项目梳理   canvas绘图系列知识点整理

图形种类

目前我们软件可以绘制出来的形状有如下这几种,作为开发者我们一直想支持用户可以拖拽的类似word里面图形库,但目前还没有找到比较合适的库。

下图中所有的图形都是我们自己写代码在canvas上绘制方法出来的,可以改变实心/空心,改变颜色,大小宽高,线条弯曲度,透明度等。

父类shape类

实现的代码如下:所有的图形均继承自shape类,而shape类继承自CommonElement,shape中的所有图形添加到画布上都是一个元素。

这个类里面有很多功能函数:

prepareStyle() { //绘制准备context绘制属性

setPro() { }//绘制前准备参数

public thiner() {//变细

public thicker() {//加粗

changeColor(color: string, callBack: Function) {//改变绘制颜色

changeAlpha(alpha: number, callBack: Function) {//改变透明度

changeFill(isFill: boolean) {//切换实心空心

drawPath() { }//绘制图形路径,所有图形都会重写该方法

draw() {//绘制调用入口

  export class Shape extends CommonElement {
shapeParameter: ShapeParameter;
tempFill: boolean;
tempStroke: boolean;
constructor(id: string, config: Config, context: CanvasRenderingContext2D, shapeParameter: ShapeParameter, typeName) {
super(id, config, context, typeName);
this.shapeParameter = shapeParameter;
}
prepareStyle() { //绘制准备context绘制属性
if (this.shapeParameter.computeLineWidth && this.shapeParameter.isStroke) {
this.shapeParameter.lineWidth = Math.max(2, Math.min(this.config.width * editor.canvas.canvasImp.scale, this.config.height * editor.canvas.canvasImp.scale) / this.shapeParameter.lineWidthScale); }
var ctx = this.context;
ctx.fillStyle = Common.Util.makeRGBA(this.shapeParameter.fillStyle, this.shapeParameter.alpha);
ctx.strokeStyle = Common.Util.makeRGBA(this.shapeParameter.strokeStyle, this.shapeParameter.alpha);
ctx.lineWidth = this.shapeParameter.lineWidth / editor.canvas.canvasImp.scale; }
public setPro() { }//绘制前准备参数
public drawPath() { }//绘制图形路径,所有图形都会重写该方法
public draw() {//绘制调用入口
//保存context状态
this.context.save();
this.rotate();//将画布旋转到位
this.setPro();
this.prepareStyle();
this.drawPath();
//恢复context状态
this.context.restore();
}

所有图形类都有的一个属性ShapeParameter 具体内容如下,每个属性值都有各自的作用

   export class ShapeParameter {//图形属性参数
lineWidth: number;
isFill: boolean;
isStroke: boolean
fillStyle: string;
strokeStyle: string
lineWidthScale: number;
isAutiClockwise: boolean;
computeLineWidth: boolean;
alpha: number;
lineDash: any;
constructor() {
this.lineWidth = 1;
this.isStroke = true;
this.isFill = false;
this.fillStyle = editor.currentShapeColor || editor.canvas.canvasImp.theme.shapeColor;
this.strokeStyle = editor.currentShapeColor || editor.canvas.canvasImp.theme.shapeColor;
this.lineWidthScale = lineWidthScale;
this.isAutiClockwise = false;
this.computeLineWidth = true;
this.alpha = editor.currentShapAlpha || 1;
this.lineDash = [10, 15];
}
}

特殊图形绘制计算方法

下面介绍几种绘制各种图形用到的特殊计算方法

如下图中的一个线条,我们可以拖拽中间控制点形成一个弧,这个弧形是某个圆的一部分。

我们定义左侧的第一个点为startPoint,中间的点为controlPoint,右侧的点为endPoint。

我们在绘制出这个图形时,需要知道如何求这三个点确定的圆的圆心坐标怎么计算,还有通过两点计算(x1,y1)为圆心,圆上某点(x2,y2)的角度的计算方法

         GetCenter(): Point {//获取三个点,确定的一个圆的中心点坐标
var p1 = this.startPoint;
var p2 = this.controlPoint;
var p3 = this.endPoint;
var C1 = new Point((p1.x + p2.x) / 2.0, (p1.y + p2.y) / 2.0);
var C2 = new Point((p2.x + p3.x) / 2.0, (p2.y + p3.y) / 2.0);
var I = new Point(0, 0);;
var k1: number, k2: number;
if ((p2.y - p1.y) == 0.0) {
if ((p3.y - p2.y) == 0.0) {
return null;
} else {
k2 = -1 * (p3.x - p2.x) / (p3.y - p2.y);
I.x = C1.x; I.y = k2 * (I.x - C2.x) + C2.y;
}
} else {
k1 = -1 * (p2.x - p1.x) / (p2.y - p1.y);
if ((p3.y - p2.y) == 0.0) {
I.x = C2.x;
I.y = k1 * (I.x - C1.x) + C1.y;
} else {
k2 = -1 * (p3.x - p2.x) / (p3.y - p2.y);
if (k1 == k2) {
return null;
} else {
I.x = (C2.y - C1.y + k1 * C1.x - k2 * C2.x) / (k1 - k2); I.y = k1 * (I.x - C1.x) + C1.y;
}
}
}
return I;
}
         //通过两点计算x1,y1为圆心,圆上某点(x2,y2)的角度(按照arc的角度计算)
static computeAng(x1, y1, x2, y2) {
var ang = (x1 - x2) / (y1 - y2);
ang = Math.atan(ang);
if (x1 == x2 && y2 > y1) {
return 0.5 * Math.PI;
}
if (x1 == x2 && y2 < y1) {
return 1.5 * Math.PI;
}
if (y1 == y2 && x2 > x1) {
return 0;
}
if (y1 == y2 && x2 < x1) {
return Math.PI;
}
if (x2 > x1 && y2 > y1) {
return Math.PI / 2 - ang;
}
else if (x2 < x1 && y2 > y1) {
return Math.PI / 2 - ang;
}
else if (x2 < x1 && y2 < y1) {
return 3 * Math.PI / 2 - ang;
}
else if (x2 > x1 && y2 < y1) {
return 3 * Math.PI / 2 - ang;
}
}

另外再介绍一下我们的这个箭头是如何实现的

         drawIsosceles(context: CanvasRenderingContext2D) {//画等腰箭头
var triangleSide = this.triangleSide;
//First the center of the triangle base (where we start to draw the triangle)
var centerBaseArrowX = this.basePoint.x ;
var centerBaseArrowY = this.basePoint.y; //Let's calculate the first point, easy!
var ax = centerBaseArrowX + (triangleSide / 2) * Math.cos(this.centerAngle);
var ay = centerBaseArrowY + (triangleSide / 2) * Math.sin(this.centerAngle); //Now time to get mad: the farest triangle point from the arrow body
var bx = centerBaseArrowX + (1/ 2/Math.sqrt(3) ) * triangleSide * (Math.sin(-this.centerAngle));
var by = centerBaseArrowY + ( 1/ 2/Math.sqrt(3)) * triangleSide * (Math.cos(-this.centerAngle)); //Easy , like the a point
var cx = centerBaseArrowX - (triangleSide / 2) * Math.cos(this.centerAngle);
var cy = centerBaseArrowY - (triangleSide / 2) * Math.sin(this.centerAngle); context.beginPath();
//We move to the center of the base
context.moveTo(centerBaseArrowX, centerBaseArrowY);
context.lineTo(ax, ay);
context.lineTo(bx, by);
context.lineTo(cx, cy);
context.lineTo(centerBaseArrowX, centerBaseArrowY);
context.fill();
}

在canvas上绘制多边形的方法

        drawPath(context: CanvasRenderingContext2D) {
for (var ixVertex = 0; ixVertex <= this.nPoints; ++ixVertex) {
var angle = ixVertex * 2 * Math.PI / this.nPoints - this.startAngle;
var point = new Point(this.centerPoint.x + this.radius * Math.cos(angle), this.centerPoint.y + this.radius * Math.sin(angle));
context.lineTo(point.x, point.y);
}
}

在canvas上绘制五角星等多角形的方法

         drawPath(context:CanvasRenderingContext2D) {
for (var ixVertex = 0; ixVertex <= 2 * this.nPoints; ++ixVertex) {
var angle = ixVertex * Math.PI / this.nPoints - Math.PI / 2;
var radius = ixVertex % 2 == 0 ? this.outerRadius : this.innerRadius;
context.lineTo(this.centerPoint.x + radius * Math.cos(angle), this.centerPoint.y + radius * Math.sin(angle));
}
}

软件项目技术点(7)——在canvas上绘制自定义图形的更多相关文章

  1. 软件项目技术点(5)——在canvas上绘制动态网格线

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 grid类的实现 当鼠标在画布上缩放时,网格能跟着我的鼠标滚动而相应的有放大缩小的效果. 下面是具体实现的代码,draw函数里计算出大 ...

  2. 软件项目技术点(6)——结合鼠标操作绘制动态canvas画布

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 我们创建一个类封装了所有鼠标需要处理的事件. export class MouseEventInfo { el: HTMLElemen ...

  3. Canvas上绘制几何图形

    重要的类自定义View组件要重写View组件的onDraw(Canvase)方法,接下来是在该 Canvas上绘制大量的几何图形,点.直线.弧.圆.椭圆.文字.矩形.多边形.曲线.圆角矩形,等各种形状 ...

  4. 软件项目技术点(2)——Canvas之平移translate、旋转rotate、缩放scale

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 画布操作介绍 画布绘图的环境通过translate(),scale(),rotate(), setTransform()和transf ...

  5. 软件项目技术点(2)——Canvas之坐标系转换

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 默认坐标系与当前坐标系 canvas中的坐标是从左上角开始的,x轴沿着水平方向(按像素)向右延伸,y轴沿垂直方向向下延伸.左上角坐标为 ...

  6. 软件项目技术点(2)——Canvas之获取Canvas当前坐标系矩阵

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 前言 在我的另一篇博文 Canvas坐标系转换 中,我们知道了所有的平移缩放旋转操作都会影响到画布坐标系.那在我们对画布进行了一系列操 ...

  7. 软件项目技术点(8)—— canvas调用drawImage绘制图片

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 html5中标签canvas,函数drawImage(): 使用drawImage()方法绘制图像.绘图环境提供了该方法的三个不同版本 ...

  8. 软件项目技术点(1)——d3.interpolateZoom-在两个点之间平滑地缩放平移

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 软件参考d3的知识点 我们在软件中主要用到d3.js的核心函数d3.interpolateZoom - 在两个点之间平滑地缩放平移.请 ...

  9. 软件项目技术点(9)——如何将gif动态图拆分绘制

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 背景介绍 我们的软件支持插入gif图片,并且展示在软件里是动态的,例如插入下面这张gif图. 在软件里显示的同样是这样的动态效果: 那 ...

随机推荐

  1. java8特性之Lambda表达式

    1.典型的用Lambda表达式的场景 如果有这样的一个小应用,其中的一个类Student包含姓名(name),性别(sex),分数(score),如下: package demo; public cl ...

  2. JAVA数据结构--快速排序

    快排概念 快速排序(英语:Quicksort),又称划分交换排序(partition-exchange sort),一种排序算法,最早由东尼·霍尔提出.在平均状况下,排序个项目要(大O符号)次比较.在 ...

  3. TensorFlow GPU 的使用

    一.TensorFlow 设备分配 1.设备分配规则 If a TensorFlow operation has both CPU and GPU implementations, the GPU d ...

  4. golang (3) 编译不同的平台文件

    Golang 支持在一个平台下生成另一个平台可执行程序的交叉编译功能. Mac下编译Linux, Windows平台的64位可执行程序: CGO_ENABLED=0 GOOS=linux GOARCH ...

  5. Eureka 高可用 - 踩坑回忆

    1.application.yml中eureka配置更改 ## Eurake 公用配置 ## 向其他注册中心注册 eureka.client.register-with-eureka=true ## ...

  6. unity 渲染第一步

    unity 不是将宇宙投影到水晶球里,而是:将整个 view frustum 投影成 一个 cube .------ <unity 渲染箴言> 观察一下,整个 view frustum 以 ...

  7. Verilog三段式状态机描述

    时序电路的状态是一个状态变量集合,这些状态变量在任意时刻的值都包含了为确定电路的未来行为而必需考虑的所有历史信息. 状态机采用VerilogHDL语言编码,建议分为三个always段完成. 三段式建模 ...

  8. 3dsmax2013卸载/安装失败/如何彻底卸载清除干净3dsmax2013注册表和文件的方法

    3dsmax2013提示安装未完成,某些产品无法安装该怎样解决呢?一些朋友在win7或者win10系统下安装3dsmax2013失败提示3dsmax2013安装未完成,某些产品无法安装,也有时候想重新 ...

  9. Oracle 通过数据字典查询系统信息

    简介:数据字典记录了数据库系统的信息,他是只读表和视图的集合,数据字典的所有者是sys用户.注:用户只能在数据字典上执行查询操作,而维护和修改是由系统自己完成的. 1.数据字典的组成:数据字典包括数据 ...

  10. c# 短链接生成

    public static string GetShortUrl(string url) { //可以自定义生成MD5加密字符传前的混合KEY string key = DateTime.Now.To ...