Commit fc4461c8 authored by wangjianfeng.yz's avatar wangjianfeng.yz

2.0.55

parent 74a9983b
declare namespace FYGE{export const VERSION = "2.0.54"; declare namespace FYGE{export const VERSION = "2.0.55";
export function cos(angle: number): number; export function cos(angle: number): number;
...@@ -570,7 +570,7 @@ export class ObservablePoint extends HashObject { ...@@ -570,7 +570,7 @@ export class ObservablePoint extends HashObject {
* @param {number} [x=0] * @param {number} [x=0]
* @param {number} [y=0] * @param {number} [y=0]
*/ */
set(x?: number, y?: number): void; set(x: number, y: number): void;
/** /**
* 从一个点复制xy * 从一个点复制xy
* *
...@@ -1357,11 +1357,6 @@ export class Polygon { ...@@ -1357,11 +1357,6 @@ export class Polygon {
* @return {Polygon} a copy of the polygon * @return {Polygon} a copy of the polygon
*/ */
clone(): Polygon; clone(): Polygon;
/**
* Closes the polygon, adding points if necessary.
*
*/
close(): void;
/** /**
* Checks whether the x and y coordinates passed to this function are contained within this polygon * Checks whether the x and y coordinates passed to this function are contained within this polygon
* *
...@@ -1954,9 +1949,23 @@ export class LineStyle extends FillStyle { ...@@ -1954,9 +1949,23 @@ export class LineStyle extends FillStyle {
width: number; width: number;
/** /**
* 线的对齐方式 * 线的对齐方式
* 默认LINE_ALIGNMENT.middle 0.5 * @default LINE_ALIGNMENT.middle 0.5
*/ */
alignment: LINE_ALIGNMENT; alignment: LINE_ALIGNMENT;
/**
* Line cap style.
* @default LINE_CAP.BUTT
*/
cap: LINE_CAP;
/**
* Line join style.
* @default LINE_JOIN.MITER
*/
join: LINE_JOIN;
/**
* Miter limit.
*/
miterLimit: number;
/** /**
* Clones the object * Clones the object
* *
...@@ -4435,11 +4444,14 @@ export class Sprite extends Container { ...@@ -4435,11 +4444,14 @@ export class Sprite extends Container {
* 0,0标识左上角,0.5,0.5表示中间,1,1表示右下角 * 0,0标识左上角,0.5,0.5表示中间,1,1表示右下角
* @member {ObservablePoint} * @member {ObservablePoint}
*/ */
get anchorTexture(): any; get anchorTexture(): ObservablePoint;
/** /**
* 设置贴图锚点,copy方法,只要value存在x、y字段就行 * 设置贴图锚点,copy方法,只要value存在x、y字段就行
*/ */
set anchorTexture(value: any); set anchorTexture(value: {
x: number;
y: number;
});
/** /**
* 获取纹理 * 获取纹理
* @member {Texture} * @member {Texture}
...@@ -4952,6 +4964,8 @@ export const GRAPHICS_CURVES: { ...@@ -4952,6 +4964,8 @@ export const GRAPHICS_CURVES: {
segmentsCount: Function; segmentsCount: Function;
} }
export function isPointsClockwise(points: ArrayLike<number>, closed?: boolean): boolean;
export class Graphics extends Container { export class Graphics extends Container {
/** /**
* 混色模式 * 混色模式
...@@ -5053,15 +5067,18 @@ export class Graphics extends Container { ...@@ -5053,15 +5067,18 @@ export class Graphics extends Container {
* @memberof Graphics# * @memberof Graphics#
* @default false * @default false
*/ */
cacheAsBitmap: boolean; private cacheAsBitmap;
/** /**
* 需与dirty一致 * 需与dirty一致
*/ */
private cacheDirty; private cacheDirty;
private _canvasBuffer; private _canvasBuffer;
_texture: Texture; private _texture;
offsetX: number; /**
offsetY: number; * Minimal distance between points that are considered different.
* Affects line tesselation.
*/
closePointEps: number;
verts: any; verts: any;
indices: any; indices: any;
private batches; private batches;
...@@ -5077,16 +5094,29 @@ export class Graphics extends Container { ...@@ -5077,16 +5094,29 @@ export class Graphics extends Container {
* @return {Graphics} * @return {Graphics}
*/ */
clone(): Graphics; clone(): Graphics;
/**
* 为了有一个和Shape保持一致的方法,也为了能加入cap等属性,但不改变原来的lineStyle
* 比Shape多了aligment方法,和native(暂时无效)
* @param color
* @param lineWidth
* @param cap
* @param join
* @param miterLimit
* @param alpha
* @param alignment - 线的居中方式,注意对于多边形,永远是朝向的左边为1,右边为0,封闭时顺时针外部1内部0,逆时针相反,canvas模式下暂时只有居中0.5
* @param native
*/
beginStroke(color?: number | string, lineWidth?: number, cap?: LINE_CAP, join?: LINE_JOIN, miterLimit?: number, alpha?: number, alignment?: LINE_ALIGNMENT, native?: boolean): this;
/** /**
* line属于附属属性,暂不写beginStroke,只要没调用过beginFill就是纯stroke * line属于附属属性,暂不写beginStroke,只要没调用过beginFill就是纯stroke
* @param {number} [lineWidth=0] - 线的粗细 * @param {number} [lineWidth=0] - 线的粗细
* @param {number} [color=0] - 线的颜色 * @param {number} [color=0] - 线的颜色
* @param {number} [alpha=1] - 线的透明度 * @param {number} [alpha=1] - 线的透明度
* @param {number} [alignment=0.5] - 线的居中方式,canvas模式下发现线显示不全,尝试设置为0或1 * @param {number} [alignment=0.5] - 线的居中方式,注意对于多边形,永远是朝向的左边为1,右边为0,封闭时顺时针外部1内部0,逆时针相反,canvas模式下暂时只有居中0.5
* @return {Graphics} * @return {Graphics}
*/ */
lineStyle(lineWidth?: number, color?: number, alpha?: number, alignment?: LINE_ALIGNMENT, native?: boolean): Graphics; lineStyle(lineWidth?: number, color?: number, alpha?: number, alignment?: LINE_ALIGNMENT, native?: boolean): Graphics;
lineTextureStyle(width?: number, texture?: Texture, color?: number, alpha?: number, matrix?: any, alignment?: number, native?: boolean): this; private lineTextureStyle;
private startPoly; private startPoly;
private finishPoly; private finishPoly;
moveTo(x: number, y: number): Graphics; moveTo(x: number, y: number): Graphics;
...@@ -5146,7 +5176,7 @@ export class Graphics extends Container { ...@@ -5146,7 +5176,7 @@ export class Graphics extends Container {
* @return {Graphics} * @return {Graphics}
*/ */
beginFill(color?: number | string, alpha?: number): Graphics; beginFill(color?: number | string, alpha?: number): Graphics;
beginTextureFill(texture?: Texture, color?: number, alpha?: number, matrix?: Matrix): this; private beginTextureFill;
/** /**
* 结束填充 * 结束填充
* @return {Graphics} * @return {Graphics}
...@@ -5158,7 +5188,7 @@ export class Graphics extends Container { ...@@ -5158,7 +5188,7 @@ export class Graphics extends Container {
*/ */
endStroke(): Graphics; endStroke(): Graphics;
/** /**
* 闭合路径 * 闭合路径,只为了画线stroke时确定是否闭合,终点和起点一致也不能算闭合,只有调用时算,fill没必要
* 只用在多边形的路径里 * 只用在多边形的路径里
* @return {Graphics} * @return {Graphics}
*/ */
...@@ -6355,11 +6385,9 @@ export class FloatDisplay extends DisplayObject { ...@@ -6355,11 +6385,9 @@ export class FloatDisplay extends DisplayObject {
} }
export class Shape extends Sprite { export class Shape extends Sprite {
canvas: HTMLCanvasElement; private canvas;
context: CanvasRenderingContext2D; private context;
dirty: boolean; private dirty;
offsetX: number;
offsetY: number;
constructor(); constructor();
/** /**
* 一个数组,每个元素也是一个数组[类型 0是属性,1是方法,名字 执行的属性或方法名,参数] * 一个数组,每个元素也是一个数组[类型 0是属性,1是方法,名字 执行的属性或方法名,参数]
...@@ -6668,14 +6696,12 @@ export function toDisplayDataURL(obj: DisplayObject, rect?: Rectangle, typeInfo ...@@ -6668,14 +6696,12 @@ export function toDisplayDataURL(obj: DisplayObject, rect?: Rectangle, typeInfo
export class TextField extends Sprite { export class TextField extends Sprite {
private static shareCanvas; private static shareCanvas;
private static shareContext; private static shareContext;
canvas: HTMLCanvasElement; private canvas;
context: CanvasRenderingContext2D; private context;
/** /**
* 与其他类不同,用了Boolean,再考虑 * 与其他类不同,用了Boolean,再考虑
*/ */
dirty: boolean; private dirty;
offsetX: number;
offsetY: number;
constructor(); constructor();
/** /**
* @property textAlpha * @property textAlpha
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
export const VERSION = "2.0.54"; export const VERSION = "2.0.55";
export function cos(angle: number): number; export function cos(angle: number): number;
...@@ -570,7 +570,7 @@ export class ObservablePoint extends HashObject { ...@@ -570,7 +570,7 @@ export class ObservablePoint extends HashObject {
* @param {number} [x=0] * @param {number} [x=0]
* @param {number} [y=0] * @param {number} [y=0]
*/ */
set(x?: number, y?: number): void; set(x: number, y: number): void;
/** /**
* 从一个点复制xy * 从一个点复制xy
* *
...@@ -1357,11 +1357,6 @@ export class Polygon { ...@@ -1357,11 +1357,6 @@ export class Polygon {
* @return {Polygon} a copy of the polygon * @return {Polygon} a copy of the polygon
*/ */
clone(): Polygon; clone(): Polygon;
/**
* Closes the polygon, adding points if necessary.
*
*/
close(): void;
/** /**
* Checks whether the x and y coordinates passed to this function are contained within this polygon * Checks whether the x and y coordinates passed to this function are contained within this polygon
* *
...@@ -1954,9 +1949,23 @@ export class LineStyle extends FillStyle { ...@@ -1954,9 +1949,23 @@ export class LineStyle extends FillStyle {
width: number; width: number;
/** /**
* 线的对齐方式 * 线的对齐方式
* 默认LINE_ALIGNMENT.middle 0.5 * @default LINE_ALIGNMENT.middle 0.5
*/ */
alignment: LINE_ALIGNMENT; alignment: LINE_ALIGNMENT;
/**
* Line cap style.
* @default LINE_CAP.BUTT
*/
cap: LINE_CAP;
/**
* Line join style.
* @default LINE_JOIN.MITER
*/
join: LINE_JOIN;
/**
* Miter limit.
*/
miterLimit: number;
/** /**
* Clones the object * Clones the object
* *
...@@ -4435,11 +4444,14 @@ export class Sprite extends Container { ...@@ -4435,11 +4444,14 @@ export class Sprite extends Container {
* 0,0标识左上角,0.5,0.5表示中间,1,1表示右下角 * 0,0标识左上角,0.5,0.5表示中间,1,1表示右下角
* @member {ObservablePoint} * @member {ObservablePoint}
*/ */
get anchorTexture(): any; get anchorTexture(): ObservablePoint;
/** /**
* 设置贴图锚点,copy方法,只要value存在x、y字段就行 * 设置贴图锚点,copy方法,只要value存在x、y字段就行
*/ */
set anchorTexture(value: any); set anchorTexture(value: {
x: number;
y: number;
});
/** /**
* 获取纹理 * 获取纹理
* @member {Texture} * @member {Texture}
...@@ -4952,6 +4964,8 @@ export const GRAPHICS_CURVES: { ...@@ -4952,6 +4964,8 @@ export const GRAPHICS_CURVES: {
segmentsCount: Function; segmentsCount: Function;
} }
export function isPointsClockwise(points: ArrayLike<number>, closed?: boolean): boolean;
export class Graphics extends Container { export class Graphics extends Container {
/** /**
* 混色模式 * 混色模式
...@@ -5053,15 +5067,18 @@ export class Graphics extends Container { ...@@ -5053,15 +5067,18 @@ export class Graphics extends Container {
* @memberof Graphics# * @memberof Graphics#
* @default false * @default false
*/ */
cacheAsBitmap: boolean; private cacheAsBitmap;
/** /**
* 需与dirty一致 * 需与dirty一致
*/ */
private cacheDirty; private cacheDirty;
private _canvasBuffer; private _canvasBuffer;
_texture: Texture; private _texture;
offsetX: number; /**
offsetY: number; * Minimal distance between points that are considered different.
* Affects line tesselation.
*/
closePointEps: number;
verts: any; verts: any;
indices: any; indices: any;
private batches; private batches;
...@@ -5077,16 +5094,29 @@ export class Graphics extends Container { ...@@ -5077,16 +5094,29 @@ export class Graphics extends Container {
* @return {Graphics} * @return {Graphics}
*/ */
clone(): Graphics; clone(): Graphics;
/**
* 为了有一个和Shape保持一致的方法,也为了能加入cap等属性,但不改变原来的lineStyle
* 比Shape多了aligment方法,和native(暂时无效)
* @param color
* @param lineWidth
* @param cap
* @param join
* @param miterLimit
* @param alpha
* @param alignment - 线的居中方式,注意对于多边形,永远是朝向的左边为1,右边为0,封闭时顺时针外部1内部0,逆时针相反,canvas模式下暂时只有居中0.5
* @param native
*/
beginStroke(color?: number | string, lineWidth?: number, cap?: LINE_CAP, join?: LINE_JOIN, miterLimit?: number, alpha?: number, alignment?: LINE_ALIGNMENT, native?: boolean): this;
/** /**
* line属于附属属性,暂不写beginStroke,只要没调用过beginFill就是纯stroke * line属于附属属性,暂不写beginStroke,只要没调用过beginFill就是纯stroke
* @param {number} [lineWidth=0] - 线的粗细 * @param {number} [lineWidth=0] - 线的粗细
* @param {number} [color=0] - 线的颜色 * @param {number} [color=0] - 线的颜色
* @param {number} [alpha=1] - 线的透明度 * @param {number} [alpha=1] - 线的透明度
* @param {number} [alignment=0.5] - 线的居中方式,canvas模式下发现线显示不全,尝试设置为0或1 * @param {number} [alignment=0.5] - 线的居中方式,注意对于多边形,永远是朝向的左边为1,右边为0,封闭时顺时针外部1内部0,逆时针相反,canvas模式下暂时只有居中0.5
* @return {Graphics} * @return {Graphics}
*/ */
lineStyle(lineWidth?: number, color?: number, alpha?: number, alignment?: LINE_ALIGNMENT, native?: boolean): Graphics; lineStyle(lineWidth?: number, color?: number, alpha?: number, alignment?: LINE_ALIGNMENT, native?: boolean): Graphics;
lineTextureStyle(width?: number, texture?: Texture, color?: number, alpha?: number, matrix?: any, alignment?: number, native?: boolean): this; private lineTextureStyle;
private startPoly; private startPoly;
private finishPoly; private finishPoly;
moveTo(x: number, y: number): Graphics; moveTo(x: number, y: number): Graphics;
...@@ -5146,7 +5176,7 @@ export class Graphics extends Container { ...@@ -5146,7 +5176,7 @@ export class Graphics extends Container {
* @return {Graphics} * @return {Graphics}
*/ */
beginFill(color?: number | string, alpha?: number): Graphics; beginFill(color?: number | string, alpha?: number): Graphics;
beginTextureFill(texture?: Texture, color?: number, alpha?: number, matrix?: Matrix): this; private beginTextureFill;
/** /**
* 结束填充 * 结束填充
* @return {Graphics} * @return {Graphics}
...@@ -5158,7 +5188,7 @@ export class Graphics extends Container { ...@@ -5158,7 +5188,7 @@ export class Graphics extends Container {
*/ */
endStroke(): Graphics; endStroke(): Graphics;
/** /**
* 闭合路径 * 闭合路径,只为了画线stroke时确定是否闭合,终点和起点一致也不能算闭合,只有调用时算,fill没必要
* 只用在多边形的路径里 * 只用在多边形的路径里
* @return {Graphics} * @return {Graphics}
*/ */
...@@ -6355,11 +6385,9 @@ export class FloatDisplay extends DisplayObject { ...@@ -6355,11 +6385,9 @@ export class FloatDisplay extends DisplayObject {
} }
export class Shape extends Sprite { export class Shape extends Sprite {
canvas: HTMLCanvasElement; private canvas;
context: CanvasRenderingContext2D; private context;
dirty: boolean; private dirty;
offsetX: number;
offsetY: number;
constructor(); constructor();
/** /**
* 一个数组,每个元素也是一个数组[类型 0是属性,1是方法,名字 执行的属性或方法名,参数] * 一个数组,每个元素也是一个数组[类型 0是属性,1是方法,名字 执行的属性或方法名,参数]
...@@ -6668,14 +6696,12 @@ export function toDisplayDataURL(obj: DisplayObject, rect?: Rectangle, typeInfo ...@@ -6668,14 +6696,12 @@ export function toDisplayDataURL(obj: DisplayObject, rect?: Rectangle, typeInfo
export class TextField extends Sprite { export class TextField extends Sprite {
private static shareCanvas; private static shareCanvas;
private static shareContext; private static shareContext;
canvas: HTMLCanvasElement; private canvas;
context: CanvasRenderingContext2D; private context;
/** /**
* 与其他类不同,用了Boolean,再考虑 * 与其他类不同,用了Boolean,再考虑
*/ */
dirty: boolean; private dirty;
offsetX: number;
offsetY: number;
constructor(); constructor();
/** /**
* @property textAlpha * @property textAlpha
......
{ {
"name": "fyge", "name": "fyge",
"version": "2.0.54", "version": "2.0.55",
"description": "canvas渲染引擎", "description": "canvas渲染引擎",
"main": "./build/fyge.min.js", "main": "./build/fyge.min.js",
"module": "./build/fyge.esm.js", "module": "./build/fyge.esm.js",
......
...@@ -520,6 +520,31 @@ ...@@ -520,6 +520,31 @@
Point类新增copy方法 Point类新增copy方法
Texture类的_rotate变私有方法,且注释了rotate的set方法,以后有办法让人为赋值显示没问题了再说 Texture类的_rotate变私有方法,且注释了rotate的set方法,以后有办法让人为赋值显示没问题了再说
2.0.55 Sprite的anchorTexture的get方法加上返回类型,anchorTexture的set方法参数加上类型{x:number,y:number}
Graphics的cacheAsBitmap和_texture变私有
Graphics去掉offsetX和offsetY(涉及generateCanvasTexture),相应CanvasSpriteRenderer里的offsetXY替换成_localBoundsSelf的xy,并加上判断instanceType=="Graphics"(是否有必要)
Graphics新增属性closePointEps,对应修改arc方法里的0.001改成该属性值,buildLine里也用到
Graphics新增beginStroke方法,除了最后的alignment和native属性,其他和Shape的一致,为了加上三个属性cap、join、miterLimit
Graphics把beginTextureFill和lineTextureStyle改成私有,解决几何里纹理的问题(图集,重复,变换等)前,不对外开放
Graphics的closePath方法修改。标记closed为true,删除Polygon里的close方法
Graphics的updateLocalBoundsSelf方法里加上调用finishPoly,然后关于lineWidth的修改较多,以后有时间再搞
Shape的canvas、context、dirty都变私有
Shape去掉offsetX和offsetY,相关使用删除,_drawShape方法里位图有矩阵时offsetXY替换成了anchorTextureXY乘canvasWH
Shape的beginStroke方法参数miter默认值改成10
buildCircle的points改成顺时针(为了buildLine统一线居中方式),sin和cos交换下
buildLine大改,为了cap,join等等
buildRoundedRectangle的build方法修改,判断radius,并改成顺时针,且去掉原先为了避免点重叠的0.0000000001,quadraticBezierCurve方法里加了判断不会重叠
RoundedRectangle的构造函数里去掉了原先为了避免点重叠的0.0000000001,待测试
LineStyle加了三个属性cap、join、miterLimit,相应clone和reset也加上
ObservablePoint的set方法修改,去掉默认赋值0和原先的y不传时就用x,单纯xy都需要传,和point的set保持一致
CanvasGraphicsRenderer的render方法新增赋值context属性lineCap,lineJoin,miterLimit,且去掉maxRadius丢弃小数操作|0
TextField的canvas、context、dirty都变私有
TextField去掉offsetX和offsetY,相关使用删除,待测试,暂时感觉没啥用,和Shape一样,原先为了CanvasSpriteRenderer里,现在这俩都用anchorTexture了
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* @name VERSION * @name VERSION
* @type {string} * @type {string}
*/ */
export const VERSION = "2.0.54"; export const VERSION = "2.0.55";
/** /**
......
...@@ -520,13 +520,13 @@ export default class Sprite extends Container { ...@@ -520,13 +520,13 @@ export default class Sprite extends Container {
* 0,0标识左上角,0.5,0.5表示中间,1,1表示右下角 * 0,0标识左上角,0.5,0.5表示中间,1,1表示右下角
* @member {ObservablePoint} * @member {ObservablePoint}
*/ */
get anchorTexture() { get anchorTexture():ObservablePoint {
return this._anchorTexture; return this._anchorTexture;
} }
/** /**
* 设置贴图锚点,copy方法,只要value存在x、y字段就行 * 设置贴图锚点,copy方法,只要value存在x、y字段就行
*/ */
set anchorTexture(value: any) { set anchorTexture(value: { x: number, y: number }) {
this._anchorTexture.copy(value); this._anchorTexture.copy(value);
} }
......
...@@ -5,7 +5,7 @@ import RenderTexture from "../texture/RenderTexture"; ...@@ -5,7 +5,7 @@ import RenderTexture from "../texture/RenderTexture";
import { Matrix, Point, Rectangle } from '../math'; import { Matrix, Point, Rectangle } from '../math';
import { RoundedRectangle, Ellipse, Polygon, Circle } from "./shapes" import { RoundedRectangle, Ellipse, Polygon, Circle } from "./shapes"
import { sign, string2hex, hex2rgb } from '../utils'; import { sign, string2hex, hex2rgb } from '../utils';
import { SHAPES, PI_2, SCALE_MODES, WRAP_MODES, BLEND_MODES, LINE_ALIGNMENT } from '../const'; import { SHAPES, PI_2, SCALE_MODES, WRAP_MODES, BLEND_MODES, LINE_ALIGNMENT, LINE_CAP, LINE_JOIN } from '../const';
import { DisplayObject } from '../display/DisplayObject'; import { DisplayObject } from '../display/DisplayObject';
import Texture from '../texture/Texture'; import Texture from '../texture/Texture';
import { CanvasRenderer } from '../renderers/CanvasRenderer'; import { CanvasRenderer } from '../renderers/CanvasRenderer';
...@@ -44,6 +44,7 @@ fillCommands[SHAPES.RREC] = buildRoundedRectangle; ...@@ -44,6 +44,7 @@ fillCommands[SHAPES.RREC] = buildRoundedRectangle;
* 自身matrix无效,暂时不用 * 自身matrix无效,暂时不用
* style的纹理matrix无效,暂时不用 * style的纹理matrix无效,暂时不用
* 最终都会按照三角形数据存储,包括画面和画线 * 最终都会按照三角形数据存储,包括画面和画线
* 对于持续画线之类的画板。画越多记录的数据越多,建议用Shape(直接一张离屏缓存),
*/ */
export default class Graphics extends Container { export default class Graphics extends Container {
/** /**
...@@ -171,18 +172,23 @@ export default class Graphics extends Container { ...@@ -171,18 +172,23 @@ export default class Graphics extends Container {
* @memberof Graphics# * @memberof Graphics#
* @default false * @default false
*/ */
cacheAsBitmap: boolean = true; private cacheAsBitmap: boolean = true;
/** /**
* 需与dirty一致 * 需与dirty一致
*/ */
private cacheDirty: number; private cacheDirty: number;
private _canvasBuffer: RenderTexture; private _canvasBuffer: RenderTexture;
//缓存的贴图 //缓存的贴图
_texture: Texture; private _texture: Texture;
//如果用缓存绘图,必须考虑偏移量; // //如果用缓存绘图,必须考虑偏移量;,直接使用_localBoundsSelf.xy
offsetX: number; // offsetX: number;
offsetY: number; // offsetY: number;
/**
* Minimal distance between points that are considered different.
* Affects line tesselation.
*/
public closePointEps = 1e-4;
//webgl专用数据 //webgl专用数据
verts; verts;
indices; indices;
...@@ -251,13 +257,43 @@ export default class Graphics extends Container { ...@@ -251,13 +257,43 @@ export default class Graphics extends Container {
return clone; return clone;
} }
/**
* 为了有一个和Shape保持一致的方法,也为了能加入cap等属性,但不改变原来的lineStyle
* 比Shape多了aligment方法,和native(暂时无效)
* @param color
* @param lineWidth
* @param cap
* @param join
* @param miterLimit
* @param alpha
* @param alignment - 线的居中方式,注意对于多边形,永远是朝向的左边为1,右边为0,封闭时顺时针外部1内部0,逆时针相反,canvas模式下暂时只有居中0.5
* @param native
*/
beginStroke(
color: number | string = 0,
lineWidth: number = 1,
cap: LINE_CAP = LINE_CAP.BUTT,
join: LINE_JOIN = LINE_JOIN.MITER,
miterLimit: number = 10,
alpha: number = 1,
alignment: LINE_ALIGNMENT = 0.5,
native: boolean = false
) {
//兼容下颜色格式
if (typeof (color) == "string") color = string2hex(color);
this.lineTextureStyle(lineWidth, Texture.WHITE, color, alpha, null, alignment, native);
//三个属性
this._lineStyle.cap = cap;
this._lineStyle.join = join;
this._lineStyle.miterLimit = miterLimit;
return this;
}
/** /**
* line属于附属属性,暂不写beginStroke,只要没调用过beginFill就是纯stroke * line属于附属属性,暂不写beginStroke,只要没调用过beginFill就是纯stroke
* @param {number} [lineWidth=0] - 线的粗细 * @param {number} [lineWidth=0] - 线的粗细
* @param {number} [color=0] - 线的颜色 * @param {number} [color=0] - 线的颜色
* @param {number} [alpha=1] - 线的透明度 * @param {number} [alpha=1] - 线的透明度
* @param {number} [alignment=0.5] - 线的居中方式,canvas模式下发现线显示不全,尝试设置为0或1 * @param {number} [alignment=0.5] - 线的居中方式,注意对于多边形,永远是朝向的左边为1,右边为0,封闭时顺时针外部1内部0,逆时针相反,canvas模式下暂时只有居中0.5
* @return {Graphics} * @return {Graphics}
*/ */
lineStyle( lineStyle(
...@@ -272,7 +308,7 @@ export default class Graphics extends Container { ...@@ -272,7 +308,7 @@ export default class Graphics extends Container {
return this; return this;
} }
lineTextureStyle( private lineTextureStyle(
width = 0, width = 0,
texture = Texture.WHITE, texture = Texture.WHITE,
color = 0xFFFFFF, color = 0xFFFFFF,
...@@ -523,6 +559,7 @@ export default class Graphics extends Container { ...@@ -523,6 +559,7 @@ export default class Graphics extends Container {
const startX = cx + (Math.cos(startAngle) * radius); const startX = cx + (Math.cos(startAngle) * radius);
const startY = cy + (Math.sin(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius);
const eps = this.closePointEps;
// If the _currentPath exists, take its points. Otherwise call `moveTo` to start a path. // If the _currentPath exists, take its points. Otherwise call `moveTo` to start a path.
let points = this._currentPath ? this._currentPath.points : null; let points = this._currentPath ? this._currentPath.points : null;
...@@ -532,7 +569,7 @@ export default class Graphics extends Container { ...@@ -532,7 +569,7 @@ export default class Graphics extends Container {
const xDiff = Math.abs(points[points.length - 2] - startX); const xDiff = Math.abs(points[points.length - 2] - startX);
const yDiff = Math.abs(points[points.length - 1] - startY); const yDiff = Math.abs(points[points.length - 1] - startY);
if (xDiff < 0.001 && yDiff < 0.001) { if (xDiff < eps && yDiff < eps) {
// If the point is very close, we don't add it, since this would lead to artifacts // If the point is very close, we don't add it, since this would lead to artifacts
// during tesselation due to floating point imprecision. // during tesselation due to floating point imprecision.
} }
...@@ -591,7 +628,7 @@ export default class Graphics extends Container { ...@@ -591,7 +628,7 @@ export default class Graphics extends Container {
return this.beginTextureFill(Texture.WHITE, color, alpha); return this.beginTextureFill(Texture.WHITE, color, alpha);
} }
beginTextureFill(texture = Texture.WHITE, color = 0xFFFFFF, alpha = 1, matrix: Matrix = null) { private beginTextureFill(texture = Texture.WHITE, color = 0xFFFFFF, alpha = 1, matrix: Matrix = null) {
if (this._currentPath) this.startPoly(); if (this._currentPath) this.startPoly();
const visible = alpha > 0; const visible = alpha > 0;
...@@ -643,14 +680,14 @@ export default class Graphics extends Container { ...@@ -643,14 +680,14 @@ export default class Graphics extends Container {
} }
/** /**
* 闭合路径 * 闭合路径,只为了画线stroke时确定是否闭合,终点和起点一致也不能算闭合,只有调用时算,fill没必要
* 只用在多边形的路径里 * 只用在多边形的路径里
* @return {Graphics} * @return {Graphics}
*/ */
closePath(): Graphics { closePath(): Graphics {
//如果下个可能要画洞,先闭合之前的路径 //如果下个可能要画洞,先闭合之前的路径
const _currentPath = this._currentPath; const _currentPath = this._currentPath;
if (this._currentPath) _currentPath.close(); if (this._currentPath) _currentPath.closed = true//_currentPath.close();
return this; return this;
} }
/** /**
...@@ -1214,6 +1251,10 @@ export default class Graphics extends Container { ...@@ -1214,6 +1251,10 @@ export default class Graphics extends Container {
updateLocalBoundsSelf() { updateLocalBoundsSelf() {
if (this.boundsDirty == this.dirty) return; if (this.boundsDirty == this.dirty) return;
this.boundsDirty = this.dirty; this.boundsDirty = this.dirty;
//以防止调用的时候没有end
this.finishPoly();
let minX = Infinity; let minX = Infinity;
let maxX = -Infinity; let maxX = -Infinity;
...@@ -1238,7 +1279,7 @@ export default class Graphics extends Container { ...@@ -1238,7 +1279,7 @@ export default class Graphics extends Container {
const alignment = lineStyle.alignment; const alignment = lineStyle.alignment;
lineWidth = lineStyle.width; lineWidth = lineStyle.width;
if (type === SHAPES.POLY) { if (type === SHAPES.POLY) {
lineWidth = lineWidth * (0.5 + Math.abs(0.5 - alignment)); // lineWidth = lineWidth * (0.5 + Math.abs(0.5 - alignment));
} }
else { else {
lineWidth = lineWidth * Math.max(0, alignment); lineWidth = lineWidth * Math.max(0, alignment);
...@@ -1248,10 +1289,10 @@ export default class Graphics extends Container { ...@@ -1248,10 +1289,10 @@ export default class Graphics extends Container {
shape = data.shape; shape = data.shape;
if (type === SHAPES.RECT || type === SHAPES.RREC) { if (type === SHAPES.RECT || type === SHAPES.RREC) {
x = shape.x - (lineWidth / 2); x = shape.x - lineWidth;
y = shape.y - (lineWidth / 2); y = shape.y - lineWidth;
w = shape.width + lineWidth; w = shape.width + lineWidth * 2;
h = shape.height + lineWidth; h = shape.height + lineWidth * 2;
minX = x < minX ? x : minX; minX = x < minX ? x : minX;
maxX = x + w > maxX ? x + w : maxX; maxX = x + w > maxX ? x + w : maxX;
...@@ -1262,8 +1303,8 @@ export default class Graphics extends Container { ...@@ -1262,8 +1303,8 @@ export default class Graphics extends Container {
else if (type === SHAPES.CIRC) { else if (type === SHAPES.CIRC) {
x = shape.x; x = shape.x;
y = shape.y; y = shape.y;
w = shape.radius + (lineWidth / 2); w = shape.radius + lineWidth;
h = shape.radius + (lineWidth / 2); h = shape.radius + lineWidth;
minX = x - w < minX ? x - w : minX; minX = x - w < minX ? x - w : minX;
maxX = x + w > maxX ? x + w : maxX; maxX = x + w > maxX ? x + w : maxX;
...@@ -1274,8 +1315,8 @@ export default class Graphics extends Container { ...@@ -1274,8 +1315,8 @@ export default class Graphics extends Container {
else if (type === SHAPES.ELIP) { else if (type === SHAPES.ELIP) {
x = shape.x; x = shape.x;
y = shape.y; y = shape.y;
w = shape.width + (lineWidth / 2); w = shape.width + lineWidth;
h = shape.height + (lineWidth / 2); h = shape.height + lineWidth;
minX = x - w < minX ? x - w : minX; minX = x - w < minX ? x - w : minX;
maxX = x + w > maxX ? x + w : maxX; maxX = x + w > maxX ? x + w : maxX;
...@@ -1285,7 +1326,8 @@ export default class Graphics extends Container { ...@@ -1285,7 +1326,8 @@ export default class Graphics extends Container {
} }
else { else {
// POLY // POLY
const points = shape.points; let poly: Polygon = shape;
const points = poly.points;
let x2 = 0; let x2 = 0;
let y2 = 0; let y2 = 0;
let dx = 0; let dx = 0;
...@@ -1314,11 +1356,56 @@ export default class Graphics extends Container { ...@@ -1314,11 +1356,56 @@ export default class Graphics extends Container {
cx = (x2 + x) / 2; cx = (x2 + x) / 2;
cy = (y2 + y) / 2; cy = (y2 + y) / 2;
//有线宽,且不居中的时候,中心点需要做偏移,下面和上面有很多重复计算
if (lineWidth && lineStyle.alignment != LINE_ALIGNMENT.middle) {
const width = lineWidth / 2;
let perpx = -(y - y2);
let perpy = x - x2;
perpx /= w;
perpy /= w;
perpx *= width;
perpy *= width;
const ratio = lineStyle.alignment;
const innerWeight = (1 - ratio);
const outerWeight = ratio;
if (ratio == LINE_ALIGNMENT.inner) {
cx -= perpx * innerWeight;
cy -= perpy * innerWeight;
} else {
cx += perpx * outerWeight;
cy += perpy * outerWeight;
}
}
minX = cx - rw < minX ? cx - rw : minX; minX = cx - rw < minX ? cx - rw : minX;
maxX = cx + rw > maxX ? cx + rw : maxX; maxX = cx + rw > maxX ? cx + rw : maxX;
minY = cy - rh < minY ? cy - rh : minY; minY = cy - rh < minY ? cy - rh : minY;
maxY = cy + rh > maxY ? cy + rh : maxY; maxY = cy + rh > maxY ? cy + rh : maxY;
//如果没有闭合,需要判断末端顶点(round和square都需要额外加点动),以后再说了TODO,不好搞,现在随便搞下先
if (lineWidth && !poly.closed) {
//第一个点
if (j == 0) {//这种方式根本就不需要上面那样的计算
minX = Math.min(minX, x - lineWidth)
maxX = Math.max(maxX, x + lineWidth)
minY = Math.min(minY, y - lineWidth)
maxY = Math.max(maxY, y + lineWidth)
}
//最后一个点
if (j + 4 == points.length) {
minX = Math.min(minX, x2 - lineWidth)
maxX = Math.max(maxX, x2 + lineWidth)
minY = Math.min(minY, y2 - lineWidth)
maxY = Math.max(maxY, y2 + lineWidth)
}
}
//还需要判断连接点,,,咋搞TODO
if (lineWidth && j + 4 !== points.length) {//只看第二个点是不是末点,不是就算下
}
} }
} }
} }
...@@ -1375,8 +1462,8 @@ export default class Graphics extends Container { ...@@ -1375,8 +1462,8 @@ export default class Graphics extends Container {
} }
//可能需要更改_texture,this._texture.baseTexture尺寸 //可能需要更改_texture,this._texture.baseTexture尺寸
this.offsetX = bounds.x; // this.offsetX = bounds.x;
this.offsetY = bounds.y; // this.offsetY = bounds.y;
return this._texture; return this._texture;
// return // return
} }
......
...@@ -18,11 +18,12 @@ import Sprite from "../display/Sprite"; ...@@ -18,11 +18,12 @@ import Sprite from "../display/Sprite";
* @extends Sprite * @extends Sprite
*/ */
export class Shape extends Sprite { export class Shape extends Sprite {
canvas: HTMLCanvasElement; private canvas: HTMLCanvasElement;
context: CanvasRenderingContext2D; private context: CanvasRenderingContext2D;
dirty: boolean; private dirty: boolean;
offsetX: number;
offsetY: number; // offsetX: number;
// offsetY: number;
constructor() { constructor() {
super(); super();
this._instanceType = "Shape"; this._instanceType = "Shape";
...@@ -399,7 +400,7 @@ export class Shape extends Sprite { ...@@ -399,7 +400,7 @@ export class Shape extends Sprite {
lineWidth: number = 1, lineWidth: number = 1,
cap: LINE_CAP = LINE_CAP.BUTT, cap: LINE_CAP = LINE_CAP.BUTT,
join: LINE_JOIN = LINE_JOIN.MITER, join: LINE_JOIN = LINE_JOIN.MITER,
miter: number = 0, miter: number = 10,
alpha: number = 1 alpha: number = 1
): this { ): this {
if (typeof (color) == "number") color = hex2string(color); if (typeof (color) == "number") color = hex2string(color);
...@@ -649,8 +650,8 @@ export class Shape extends Sprite { ...@@ -649,8 +650,8 @@ export class Shape extends Sprite {
buttonRightY += 20 + lineWidth >> 1; buttonRightY += 20 + lineWidth >> 1;
let w = buttonRightX - leftX; let w = buttonRightX - leftX;
let h = buttonRightY - leftY; let h = buttonRightY - leftY;
s.offsetX = leftX; // s.offsetX = leftX;
s.offsetY = leftY; // s.offsetY = leftY;
// s._localBoundsSelf.x = leftX + 10;//下面anchorTexture的设置会更新(且还是原来的错误的纹理尺寸),s.texture.update()里也会更新了 // s._localBoundsSelf.x = leftX + 10;//下面anchorTexture的设置会更新(且还是原来的错误的纹理尺寸),s.texture.update()里也会更新了
// s._localBoundsSelf.y = leftY + 10; // s._localBoundsSelf.y = leftY + 10;
// s._localBoundsSelf.width = w - 20; // s._localBoundsSelf.width = w - 20;
...@@ -667,8 +668,8 @@ export class Shape extends Sprite { ...@@ -667,8 +668,8 @@ export class Shape extends Sprite {
} else { } else {
s.canvas.width = 0; s.canvas.width = 0;
s.canvas.height = 0; s.canvas.height = 0;
s.offsetX = 0; // s.offsetX = 0;
s.offsetY = 0; // s.offsetY = 0;
// s._localBoundsSelf.clear();//下面anchorTexture的设置会更新(且还是原来的错误的纹理尺寸),s.texture.update()里也会更新了 // s._localBoundsSelf.clear();//下面anchorTexture的设置会更新(且还是原来的错误的纹理尺寸),s.texture.update()里也会更新了
s.anchorTexture.set(0, 0) //= { x: 0, y: 0 }; s.anchorTexture.set(0, 0) //= { x: 0, y: 0 };
} }
...@@ -689,8 +690,8 @@ export class Shape extends Sprite { ...@@ -689,8 +690,8 @@ export class Shape extends Sprite {
let com = s._command; let com = s._command;
let cLen = com.length; let cLen = com.length;
let data: any; let data: any;
let leftX: number = s.offsetX; // let leftX: number = s.offsetX;
let leftY: number = s.offsetY; // let leftY: number = s.offsetY;
for (let i = 0; i < cLen; i++) { for (let i = 0; i < cLen; i++) {
data = com[i]; data = com[i];
if (data[0] > 0) { if (data[0] > 0) {
...@@ -708,8 +709,11 @@ export class Shape extends Sprite { ...@@ -708,8 +709,11 @@ export class Shape extends Sprite {
let ly = data[2][5]; let ly = data[2][5];
if (data[0] == 2) { if (data[0] == 2) {
//位图填充 //位图填充
lx -= leftX; // lx -= leftX;
ly -= leftY; // ly -= leftY;
//位图填充是也有矩阵,导致_drawShape之前设置的setTransform里的-leftX, -leftY无效,所以这里额外处理,待测试
lx += s.anchorTexture.x * s.canvas.width;
lx += s.anchorTexture.y * s.canvas.height;
} }
ctx[data[1]](data[2][0], data[2][1], data[2][2], data[2][3], lx, ly); ctx[data[1]](data[2][0], data[2][1], data[2][2], data[2][3], lx, ly);
} }
......
...@@ -43,16 +43,23 @@ export default { ...@@ -43,16 +43,23 @@ export default {
} }
let totalSegs = Math.floor(30 * Math.sqrt(circleData.radius)) let totalSegs = Math.floor(30 * Math.sqrt(circleData.radius))
|| Math.floor(15 * Math.sqrt(circleData.width + circleData.height)); || Math.floor(15 * Math.sqrt(width + height));
totalSegs /= 2.3; totalSegs /= 2.3;
const seg = (Math.PI * 2) / totalSegs; const seg = (Math.PI * 2) / totalSegs;
for (let i = 0; i < totalSegs; i++) { // for (let i = 0; i < totalSegs; i++) {
points.push( // points.push(
x + (Math.sin(seg * i) * width), // x + (Math.sin(seg * i) * width),
y + (Math.cos(seg * i) * height) // y + (Math.cos(seg * i) * height)
// );
// }
//20211220修改
for (let i = 0; i < totalSegs - 0.5; i++) {
points.push(//顺时针
x + (Math.cos(seg * i) * width),
y + (Math.sin(seg * i) * height)
); );
} }
...@@ -62,7 +69,7 @@ export default { ...@@ -62,7 +69,7 @@ export default {
); );
}, },
triangulate(graphicsData, graphicsGeometry:Graphics) { triangulate(graphicsData, graphicsGeometry: Graphics) {
const points = graphicsData.points; const points = graphicsData.points;
const verts = graphicsGeometry.verts; const verts = graphicsGeometry.verts;
const indices = graphicsGeometry.indices; const indices = graphicsGeometry.indices;
......
import GraphicsData from "../GraphicsData"; import GraphicsData from "../GraphicsData";
import Graphics from "../Graphics"; import Graphics from "../Graphics";
import { Point } from "../../math"; import { Point } from "../../math";
import { SHAPES } from "../../const"; import { LINE_CAP, LINE_JOIN, SHAPES } from "../../const";
import { Polygon } from "../shapes";
/** /**
* Builds a line to draw * Buffers vertices to draw a square cap.
* *
* Ignored from docs since it is not directly exposed. * Ignored from docs since it is not directly exposed.
* *
* @ignore * @ignore
* @private * @private
* @param {WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties * @param {number} x - X-coord of end point
* @param {object} webGLData - an object containing all the WebGL-specific information to create this shape * @param {number} y - Y-coord of end point
* @param {object} webGLDataNativeLines - an object containing all the WebGL-specific information to create nativeLines * @param {number} nx - X-coord of line normal pointing inside
* @param {number} ny - Y-coord of line normal pointing inside
* @param {Array<number>} verts - vertex buffer
* @returns {}
*/ */
export default function (graphicsData: GraphicsData, graphicsGeometry: Graphics) { function square(
// if (graphicsData.lineStyle.native) x: number,
// { y: number,
// buildNativeLine(graphicsData, graphicsGeometry); nx: number,
// } ny: number,
// else innerWeight: number,
// { outerWeight: number,
buildLine(graphicsData, graphicsGeometry); clockwise: boolean, /* rotation for square (true at left end, false at right end) */
// } verts: Array<number>
): number {
const ix = x - (nx * innerWeight);
const iy = y - (ny * innerWeight);
const ox = x + (nx * outerWeight);
const oy = y + (ny * outerWeight);
/* Rotate nx,ny for extension vector */
let exx; let
eyy;
if (clockwise) {
exx = ny;
eyy = -nx;
}
else {
exx = -ny;
eyy = nx;
}
/* [i|0]x,y extended at cap */
const eix = ix + exx;
const eiy = iy + eyy;
const eox = ox + exx;
const eoy = oy + eyy;
/* Square itself must be inserted clockwise*/
verts.push(eix, eiy);
verts.push(eox, eoy);
return 2;
} }
/** /**
* Builds a line to draw using the polygon method. * Buffers vertices to draw an arc at the line joint or cap.
* *
* Ignored from docs since it is not directly exposed. * Ignored from docs since it is not directly exposed.
* *
* @ignore * @ignore
* @private * @private
* @param {GraphicsData} graphicsData - The graphics object containing all the necessary properties * @param {number} cx - X-coord of center
* @param {GraphicsGeometry} graphicsGeometry - Geometry where to append output * @param {number} cy - Y-coord of center
* @param {number} sx - X-coord of arc start
* @param {number} sy - Y-coord of arc start
* @param {number} ex - X-coord of arc end
* @param {number} ey - Y-coord of arc end
* @param {Array<number>} verts - buffer of vertices
* @param {boolean} clockwise - orientation of vertices
* @returns {number} - no. of vertices pushed
*/ */
function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) { function round(
const shape = graphicsData.shape; cx: number,
cy: number,
sx: number,
sy: number,
ex: number,
ey: number,
verts: Array<number>,
clockwise: boolean, /* if not cap, then clockwise is turn of joint, otherwise rotation from angle0 to angle1 */
): number {
const cx2p0x = sx - cx;
const cy2p0y = sy - cy;
let angle0 = Math.atan2(cx2p0x, cy2p0y);
let angle1 = Math.atan2(ex - cx, ey - cy);
if (clockwise && angle0 < angle1) {
angle0 += Math.PI * 2;
}
else if (!clockwise && angle0 > angle1) {
angle1 += Math.PI * 2;
}
let startAngle = angle0;
const angleDiff = angle1 - angle0;
const absAngleDiff = Math.abs(angleDiff);
/* if (absAngleDiff >= PI_LBOUND && absAngleDiff <= PI_UBOUND)
{
const r1x = cx - nxtPx;
const r1y = cy - nxtPy;
if (r1x === 0)
{
if (r1y > 0)
{
angleDiff = -angleDiff;
}
}
else if (r1x >= -GRAPHICS_CURVES.epsilon)
{
angleDiff = -angleDiff;
}
}*/
const radius = Math.sqrt((cx2p0x * cx2p0x) + (cy2p0y * cy2p0y));
const segCount = ((15 * absAngleDiff * Math.sqrt(radius) / Math.PI) >> 0) + 1;
const angleInc = angleDiff / segCount;
startAngle += angleInc;
if (clockwise) {
verts.push(cx, cy);
verts.push(sx, sy);
for (let i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) {
verts.push(cx, cy);
verts.push(cx + ((Math.sin(angle) * radius)),
cy + ((Math.cos(angle) * radius)));
}
verts.push(cx, cy);
verts.push(ex, ey);
}
else {
verts.push(sx, sy);
verts.push(cx, cy);
for (let i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) {
verts.push(cx + ((Math.sin(angle) * radius)),
cy + ((Math.cos(angle) * radius)));
verts.push(cx, cy);
}
verts.push(ex, ey);
verts.push(cx, cy);
}
return segCount * 2;
}
function buildNonNativeLine(graphicsData: GraphicsData, graphicsGeometry: Graphics): void {
const shape = graphicsData.shape as Polygon;
let points = graphicsData.points || shape.points.slice(); let points = graphicsData.points || shape.points.slice();
const eps = graphicsGeometry.closePointEps;
if (points.length === 0) { if (points.length === 0) {
return; return;
...@@ -59,10 +183,11 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) { ...@@ -59,10 +183,11 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) {
const firstPoint = new Point(points[0], points[1]); const firstPoint = new Point(points[0], points[1]);
const lastPoint = new Point(points[points.length - 2], points[points.length - 1]); const lastPoint = new Point(points[points.length - 2], points[points.length - 1]);
const closedShape = shape.type !== SHAPES.POLY || shape.closed; const closedShape = shape.type !== SHAPES.POLY || shape.closed;
const closedPath = firstPoint.x === lastPoint.x && firstPoint.y === lastPoint.y; const closedPath = Math.abs(firstPoint.x - lastPoint.x) < eps
&& Math.abs(firstPoint.y - lastPoint.y) < eps;
// if the first point is the last point - gonna have issues :) // if the first point is the last point - gonna have issues :)
if (closedPath || closedShape) { if (closedShape) {
// need to clone as we are going to slightly modify the shape.. // need to clone as we are going to slightly modify the shape..
points = points.slice(); points = points.slice();
...@@ -72,8 +197,8 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) { ...@@ -72,8 +197,8 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) {
lastPoint.set(points[points.length - 2], points[points.length - 1]); lastPoint.set(points[points.length - 2], points[points.length - 1]);
} }
const midPointX = lastPoint.x + ((firstPoint.x - lastPoint.x) * 0.5); const midPointX = (firstPoint.x + lastPoint.x) * 0.5;
const midPointY = lastPoint.y + ((firstPoint.y - lastPoint.y) * 0.5); const midPointY = (lastPoint.y + firstPoint.y) * 0.5;
points.unshift(midPointX, midPointY); points.unshift(midPointX, midPointY);
points.push(midPointX, midPointY); points.push(midPointX, midPointY);
...@@ -82,25 +207,26 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) { ...@@ -82,25 +207,26 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) {
const verts = graphicsGeometry.verts; const verts = graphicsGeometry.verts;
const length = points.length / 2; const length = points.length / 2;
let indexCount = points.length; let indexCount = points.length;
let indexStart = verts.length / 2; const indexStart = verts.length / 2;
// DRAW the Line // Max. inner and outer width
const width = style.width / 2; const width = style.width / 2;
const widthSquared = width * width;
// sort color const miterLimitSquared = style.miterLimit * style.miterLimit;
let p1x = points[0];
let p1y = points[1]; /* Line segments of interest where (x1,y1) forms the corner. */
let p2x = points[2]; let x0 = points[0];
let p2y = points[3]; let y0 = points[1];
let p3x = 0; let x1 = points[2];
let p3y = 0; let y1 = points[3];
let x2 = 0;
let perpx = -(p1y - p2y); let y2 = 0;
let perpy = p1x - p2x;
let perp2x = 0; /* perp[?](x|y) = the line normal with magnitude lineWidth. */
let perp2y = 0; let perpx = -(y0 - y1);
let perp3x = 0; let perpy = x0 - x1;
let perp3y = 0; let perp1x = 0;
let perp1y = 0;
let dist = Math.sqrt((perpx * perpx) + (perpy * perpy)); let dist = Math.sqrt((perpx * perpx) + (perpy * perpy));
...@@ -110,30 +236,47 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) { ...@@ -110,30 +236,47 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) {
perpy *= width; perpy *= width;
const ratio = style.alignment;// 0.5; const ratio = style.alignment;// 0.5;
const r1 = (1 - ratio) * 2; const innerWeight = (1 - ratio) * 2;
const r2 = ratio * 2; const outerWeight = ratio * 2;
if (!closedShape) {
if (style.cap === LINE_CAP.ROUND) {
indexCount += round(
x0 - (perpx * (innerWeight - outerWeight) * 0.5),
y0 - (perpy * (innerWeight - outerWeight) * 0.5),
x0 - (perpx * innerWeight),
y0 - (perpy * innerWeight),
x0 + (perpx * outerWeight),
y0 + (perpy * outerWeight),
verts,
true,
) + 2;
}
else if (style.cap === LINE_CAP.SQUARE) {
indexCount += square(x0, y0, perpx, perpy, innerWeight, outerWeight, true, verts);
}
}
// start // Push first point (below & above vertices)
verts.push( verts.push(
p1x - (perpx * r1), x0 - (perpx * innerWeight),
p1y - (perpy * r1)); y0 - (perpy * innerWeight));
verts.push( verts.push(
p1x + (perpx * r2), x0 + (perpx * outerWeight),
p1y + (perpy * r2)); y0 + (perpy * outerWeight));
for (let i = 1; i < length - 1; ++i) { for (let i = 1; i < length - 1; ++i) {
p1x = points[(i - 1) * 2]; x0 = points[(i - 1) * 2];
p1y = points[((i - 1) * 2) + 1]; y0 = points[((i - 1) * 2) + 1];
p2x = points[i * 2]; x1 = points[i * 2];
p2y = points[(i * 2) + 1]; y1 = points[(i * 2) + 1];
p3x = points[(i + 1) * 2]; x2 = points[(i + 1) * 2];
p3y = points[((i + 1) * 2) + 1]; y2 = points[((i + 1) * 2) + 1];
perpx = -(p1y - p2y); perpx = -(y0 - y1);
perpy = p1x - p2x; perpy = x0 - x1;
dist = Math.sqrt((perpx * perpx) + (perpy * perpy)); dist = Math.sqrt((perpx * perpx) + (perpy * perpy));
perpx /= dist; perpx /= dist;
...@@ -141,74 +284,159 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) { ...@@ -141,74 +284,159 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) {
perpx *= width; perpx *= width;
perpy *= width; perpy *= width;
perp2x = -(p2y - p3y); perp1x = -(y1 - y2);
perp2y = p2x - p3x; perp1y = x1 - x2;
dist = Math.sqrt((perp2x * perp2x) + (perp2y * perp2y)); dist = Math.sqrt((perp1x * perp1x) + (perp1y * perp1y));
perp2x /= dist; perp1x /= dist;
perp2y /= dist; perp1y /= dist;
perp2x *= width; perp1x *= width;
perp2y *= width; perp1y *= width;
const a1 = (-perpy + p1y) - (-perpy + p2y); /* d[x|y](0|1) = the component displacement between points p(0,1|1,2) */
const b1 = (-perpx + p2x) - (-perpx + p1x); const dx0 = x1 - x0;
const c1 = ((-perpx + p1x) * (-perpy + p2y)) - ((-perpx + p2x) * (-perpy + p1y)); const dy0 = y0 - y1;
const a2 = (-perp2y + p3y) - (-perp2y + p2y); const dx1 = x1 - x2;
const b2 = (-perp2x + p2x) - (-perp2x + p3x); const dy1 = y2 - y1;
const c2 = ((-perp2x + p3x) * (-perp2y + p2y)) - ((-perp2x + p2x) * (-perp2y + p3y));
let denom = (a1 * b2) - (a2 * b1); /* +ve if internal angle counterclockwise, -ve if internal angle clockwise. */
const cross = (dy0 * dx1) - (dy1 * dx0);
const clockwise = (cross < 0);
if (Math.abs(denom) < 0.1) { /* Going nearly straight? */
denom += 10.1; if (Math.abs(cross) < 0.1) {
verts.push( verts.push(
p2x - (perpx * r1), x1 - (perpx * innerWeight),
p2y - (perpy * r1)); y1 - (perpy * innerWeight));
verts.push( verts.push(
p2x + (perpx * r2), x1 + (perpx * outerWeight),
p2y + (perpy * r2)); y1 + (perpy * outerWeight));
continue; continue;
} }
const px = ((b1 * c2) - (b2 * c1)) / denom; /* p[x|y] is the miter point. pdist is the distance between miter point and p1. */
const py = ((a2 * c1) - (a1 * c2)) / denom; const c1 = ((-perpx + x0) * (-perpy + y1)) - ((-perpx + x1) * (-perpy + y0));
const pdist = ((px - p2x) * (px - p2x)) + ((py - p2y) * (py - p2y)); const c2 = ((-perp1x + x2) * (-perp1y + y1)) - ((-perp1x + x1) * (-perp1y + y2));
const px = ((dx0 * c2) - (dx1 * c1)) / cross;
if (pdist > (196 * width * width)) { const py = ((dy1 * c1) - (dy0 * c2)) / cross;
perp3x = perpx - perp2x; const pdist = ((px - x1) * (px - x1)) + ((py - y1) * (py - y1));
perp3y = perpy - perp2y;
/* Inner miter point */
dist = Math.sqrt((perp3x * perp3x) + (perp3y * perp3y)); const imx = x1 + ((px - x1) * innerWeight);
perp3x /= dist; const imy = y1 + ((py - y1) * innerWeight);
perp3y /= dist; /* Outer miter point */
perp3x *= width; const omx = x1 - ((px - x1) * outerWeight);
perp3y *= width; const omy = y1 - ((py - y1) * outerWeight);
verts.push(p2x - (perp3x * r1), p2y - (perp3y * r1)); /* Is the inside miter point too far away, creating a spike? */
const smallerInsideSegmentSq = Math.min((dx0 * dx0) + (dy0 * dy0), (dx1 * dx1) + (dy1 * dy1));
verts.push(p2x + (perp3x * r2), p2y + (perp3y * r2)); const insideWeight = clockwise ? innerWeight : outerWeight;
const smallerInsideDiagonalSq = smallerInsideSegmentSq + (insideWeight * insideWeight * widthSquared);
verts.push(p2x - (perp3x * r2 * r1), p2y - (perp3y * r1)); const insideMiterOk = pdist <= smallerInsideDiagonalSq;
indexCount++; if (insideMiterOk) {
if (style.join === LINE_JOIN.BEVEL || pdist / widthSquared > miterLimitSquared) {
if (clockwise) /* rotating at inner angle */ {
verts.push(imx, imy);// inner miter point
verts.push(x1 + (perpx * outerWeight), y1 + (perpy * outerWeight));// first segment's outer vertex
verts.push(imx, imy);// inner miter point
verts.push(x1 + (perp1x * outerWeight), y1 + (perp1y * outerWeight));// second segment's outer vertex
}
else /* rotating at outer angle */ {
verts.push(x1 - (perpx * innerWeight), y1 - (perpy * innerWeight));// first segment's inner vertex
verts.push(omx, omy);// outer miter point
verts.push(x1 - (perp1x * innerWeight), y1 - (perp1y * innerWeight));// second segment's outer vertex
verts.push(omx, omy);// outer miter point
}
indexCount += 2;
}
else if (style.join === LINE_JOIN.ROUND) {
if (clockwise) /* arc is outside */ {
verts.push(imx, imy);
verts.push(x1 + (perpx * outerWeight), y1 + (perpy * outerWeight));
indexCount += round(
x1, y1,
x1 + (perpx * outerWeight), y1 + (perpy * outerWeight),
x1 + (perp1x * outerWeight), y1 + (perp1y * outerWeight),
verts, true
) + 4;
verts.push(imx, imy);
verts.push(x1 + (perp1x * outerWeight), y1 + (perp1y * outerWeight));
}
else /* arc is inside */ {
verts.push(x1 - (perpx * innerWeight), y1 - (perpy * innerWeight));
verts.push(omx, omy);
indexCount += round(
x1, y1,
x1 - (perpx * innerWeight), y1 - (perpy * innerWeight),
x1 - (perp1x * innerWeight), y1 - (perp1y * innerWeight),
verts, false
) + 4;
verts.push(x1 - (perp1x * innerWeight), y1 - (perp1y * innerWeight));
verts.push(omx, omy);
}
}
else {
verts.push(imx, imy);
verts.push(omx, omy);
}
} }
else { else // inside miter is NOT ok
verts.push(p2x + ((px - p2x) * r1), p2y + ((py - p2y) * r1)); {
verts.push(x1 - (perpx * innerWeight), y1 - (perpy * innerWeight)); // first segment's inner vertex
verts.push(p2x - ((px - p2x) * r2), p2y - ((py - p2y) * r2)); verts.push(x1 + (perpx * outerWeight), y1 + (perpy * outerWeight)); // first segment's outer vertex
if (style.join === LINE_JOIN.BEVEL || pdist / widthSquared > miterLimitSquared) {
// Nothing needed
}
else if (style.join === LINE_JOIN.ROUND) {
if (clockwise) /* arc is outside */ {
indexCount += round(
x1, y1,
x1 + (perpx * outerWeight), y1 + (perpy * outerWeight),
x1 + (perp1x * outerWeight), y1 + (perp1y * outerWeight),
verts, true
) + 2;
}
else /* arc is inside */ {
indexCount += round(
x1, y1,
x1 - (perpx * innerWeight), y1 - (perpy * innerWeight),
x1 - (perp1x * innerWeight), y1 - (perp1y * innerWeight),
verts, false
) + 2;
}
}
else {
if (clockwise) {
verts.push(omx, omy); // inner miter point
verts.push(omx, omy); // inner miter point
}
else {
verts.push(imx, imy); // outer miter point
verts.push(imx, imy); // outer miter point
}
indexCount += 2;
}
verts.push(x1 - (perp1x * innerWeight), y1 - (perp1y * innerWeight)); // second segment's inner vertex
verts.push(x1 + (perp1x * outerWeight), y1 + (perp1y * outerWeight)); // second segment's outer vertex
indexCount += 2;
} }
} }
p1x = points[(length - 2) * 2]; x0 = points[(length - 2) * 2];
p1y = points[((length - 2) * 2) + 1]; y0 = points[((length - 2) * 2) + 1];
p2x = points[(length - 1) * 2]; x1 = points[(length - 1) * 2];
p2y = points[((length - 1) * 2) + 1]; y1 = points[((length - 1) * 2) + 1];
perpx = -(p1y - p2y); perpx = -(y0 - y1);
perpy = p1x - p2x; perpy = x0 - x1;
dist = Math.sqrt((perpx * perpx) + (perpy * perpy)); dist = Math.sqrt((perpx * perpx) + (perpy * perpy));
perpx /= dist; perpx /= dist;
...@@ -216,18 +444,47 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) { ...@@ -216,18 +444,47 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) {
perpx *= width; perpx *= width;
perpy *= width; perpy *= width;
verts.push(p2x - (perpx * r1), p2y - (perpy * r1)); verts.push(x1 - (perpx * innerWeight), y1 - (perpy * innerWeight));
verts.push(x1 + (perpx * outerWeight), y1 + (perpy * outerWeight));
verts.push(p2x + (perpx * r2), p2y + (perpy * r2));
if (!closedShape) {
if (style.cap === LINE_CAP.ROUND) {
indexCount += round(
x1 - (perpx * (innerWeight - outerWeight) * 0.5),
y1 - (perpy * (innerWeight - outerWeight) * 0.5),
x1 - (perpx * innerWeight),
y1 - (perpy * innerWeight),
x1 + (perpx * outerWeight),
y1 + (perpy * outerWeight),
verts,
false
) + 2;
}
else if (style.cap === LINE_CAP.SQUARE) {
indexCount += square(x1, y1, perpx, perpy, innerWeight, outerWeight, false, verts);
}
}
const indices = graphicsGeometry.indices; const indices = graphicsGeometry.indices;
const eps2 = eps * eps;
// indices.push(indexStart); // indices.push(indexStart);
for (let i = indexStart; i < indexCount + indexStart - 2; ++i) {
x0 = verts[(i * 2)];
y0 = verts[(i * 2) + 1];
x1 = verts[(i + 1) * 2];
y1 = verts[((i + 1) * 2) + 1];
for (let i = 0; i < indexCount - 2; ++i) { x2 = verts[(i + 2) * 2];
indices.push(indexStart, indexStart + 1, indexStart + 2); y2 = verts[((i + 2) * 2) + 1];
/* Skip zero area triangles */
if (Math.abs((x0 * (y1 - y2)) + (x1 * (y2 - y0)) + (x2 * (y0 - y1))) < eps2) {
continue;
}
indexStart++; indices.push(i, i + 1, i + 2);
} }
} }
...@@ -238,34 +495,45 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) { ...@@ -238,34 +495,45 @@ function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) {
* *
* @ignore * @ignore
* @private * @private
* @param {WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties * @param {PIXI.GraphicsData} graphicsData - The graphics object containing all the necessary properties
* @param {object} webGLData - an object containing all the WebGL-specific information to create this shape * @param {PIXI.GraphicsGeometry} graphicsGeometry - Geometry where to append output
*/ */
function buildNativeLine(graphicsData, graphicsGeometry) { function buildNativeLine(graphicsData: GraphicsData, graphicsGeometry: Graphics): void {
let i = 0; let i = 0;
const points = graphicsData.points || graphicsData.shape.points; const shape = graphicsData.shape as Polygon;
const points = graphicsData.points || shape.points;
const closedShape = shape.type !== SHAPES.POLY || shape.closed;
if (points.length === 0) return; if (points.length === 0) return;
const verts = graphicsGeometry.points; const verts = graphicsGeometry.verts;
const indices = graphicsGeometry.indices; const indices = graphicsGeometry.indices;
const length = points.length / 2; const length = points.length / 2;
let indexStart = verts.length / 2; const startIndex = verts.length / 2;
// sort color let currentIndex = startIndex;
verts.push(points[0], points[1]);
for (i = 1; i < length; i++) { for (i = 1; i < length; i++) {
const p1x = points[(i - 1) * 2]; verts.push(points[i * 2], points[(i * 2) + 1]);
const p1y = points[((i - 1) * 2) + 1]; indices.push(currentIndex, currentIndex + 1);
const p2x = points[i * 2]; currentIndex++;
const p2y = points[(i * 2) + 1]; }
verts.push(p1x, p1y); if (closedShape) {
indices.push(currentIndex, startIndex);
}
}
verts.push(p2x, p2y);
indices.push(indexStart++, indexStart++); export default function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics): void {
} // if (graphicsData.lineStyle.native) {
// buildNativeLine(graphicsData, graphicsGeometry);
// }
// else {
buildNonNativeLine(graphicsData, graphicsGeometry);
// }
} }
import GraphicsData from "../GraphicsData";
import Graphics from "../Graphics";
import { Point } from "../../math";
import { SHAPES } from "../../const";
/**
* Builds a line to draw
*
* Ignored from docs since it is not directly exposed.
*
* @ignore
* @private
* @param {WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties
* @param {object} webGLData - an object containing all the WebGL-specific information to create this shape
* @param {object} webGLDataNativeLines - an object containing all the WebGL-specific information to create nativeLines
*/
export default function (graphicsData: GraphicsData, graphicsGeometry: Graphics) {
// if (graphicsData.lineStyle.native)
// {
// buildNativeLine(graphicsData, graphicsGeometry);
// }
// else
// {
buildLine(graphicsData, graphicsGeometry);
// }
}
/**
* Builds a line to draw using the polygon method.
*
* Ignored from docs since it is not directly exposed.
*
* @ignore
* @private
* @param {GraphicsData} graphicsData - The graphics object containing all the necessary properties
* @param {GraphicsGeometry} graphicsGeometry - Geometry where to append output
*/
function buildLine(graphicsData: GraphicsData, graphicsGeometry: Graphics) {
const shape = graphicsData.shape;
let points = graphicsData.points || shape.points.slice();
if (points.length === 0) {
return;
}
// if the line width is an odd number add 0.5 to align to a whole pixel
// commenting this out fixes #711 and #1620
// if (graphicsData.lineWidth%2)
// {
// for (i = 0; i < points.length; i++)
// {
// points[i] += 0.5;
// }
// }
const style = graphicsData.lineStyle;
// get first and last point.. figure out the middle!
const firstPoint = new Point(points[0], points[1]);
const lastPoint = new Point(points[points.length - 2], points[points.length - 1]);
const closedShape = shape.type !== SHAPES.POLY || shape.closed;
const closedPath = firstPoint.x === lastPoint.x && firstPoint.y === lastPoint.y;
// if the first point is the last point - gonna have issues :)
if (closedPath || closedShape) {
// need to clone as we are going to slightly modify the shape..
points = points.slice();
if (closedPath) {
points.pop();
points.pop();
lastPoint.set(points[points.length - 2], points[points.length - 1]);
}
const midPointX = lastPoint.x + ((firstPoint.x - lastPoint.x) * 0.5);
const midPointY = lastPoint.y + ((firstPoint.y - lastPoint.y) * 0.5);
points.unshift(midPointX, midPointY);
points.push(midPointX, midPointY);
}
const verts = graphicsGeometry.verts;
const length = points.length / 2;
let indexCount = points.length;
let indexStart = verts.length / 2;
// DRAW the Line
const width = style.width / 2;
// sort color
let p1x = points[0];
let p1y = points[1];
let p2x = points[2];
let p2y = points[3];
let p3x = 0;
let p3y = 0;
let perpx = -(p1y - p2y);
let perpy = p1x - p2x;
let perp2x = 0;
let perp2y = 0;
let perp3x = 0;
let perp3y = 0;
let dist = Math.sqrt((perpx * perpx) + (perpy * perpy));
perpx /= dist;
perpy /= dist;
perpx *= width;
perpy *= width;
const ratio = style.alignment;// 0.5;
const r1 = (1 - ratio) * 2;
const r2 = ratio * 2;
// start
verts.push(
p1x - (perpx * r1),
p1y - (perpy * r1));
verts.push(
p1x + (perpx * r2),
p1y + (perpy * r2));
for (let i = 1; i < length - 1; ++i) {
p1x = points[(i - 1) * 2];
p1y = points[((i - 1) * 2) + 1];
p2x = points[i * 2];
p2y = points[(i * 2) + 1];
p3x = points[(i + 1) * 2];
p3y = points[((i + 1) * 2) + 1];
perpx = -(p1y - p2y);
perpy = p1x - p2x;
dist = Math.sqrt((perpx * perpx) + (perpy * perpy));
perpx /= dist;
perpy /= dist;
perpx *= width;
perpy *= width;
perp2x = -(p2y - p3y);
perp2y = p2x - p3x;
dist = Math.sqrt((perp2x * perp2x) + (perp2y * perp2y));
perp2x /= dist;
perp2y /= dist;
perp2x *= width;
perp2y *= width;
const a1 = (-perpy + p1y) - (-perpy + p2y);
const b1 = (-perpx + p2x) - (-perpx + p1x);
const c1 = ((-perpx + p1x) * (-perpy + p2y)) - ((-perpx + p2x) * (-perpy + p1y));
const a2 = (-perp2y + p3y) - (-perp2y + p2y);
const b2 = (-perp2x + p2x) - (-perp2x + p3x);
const c2 = ((-perp2x + p3x) * (-perp2y + p2y)) - ((-perp2x + p2x) * (-perp2y + p3y));
let denom = (a1 * b2) - (a2 * b1);
if (Math.abs(denom) < 0.1) {
denom += 10.1;
verts.push(
p2x - (perpx * r1),
p2y - (perpy * r1));
verts.push(
p2x + (perpx * r2),
p2y + (perpy * r2));
continue;
}
const px = ((b1 * c2) - (b2 * c1)) / denom;
const py = ((a2 * c1) - (a1 * c2)) / denom;
const pdist = ((px - p2x) * (px - p2x)) + ((py - p2y) * (py - p2y));
if (pdist > (196 * width * width)) {
perp3x = perpx - perp2x;
perp3y = perpy - perp2y;
dist = Math.sqrt((perp3x * perp3x) + (perp3y * perp3y));
perp3x /= dist;
perp3y /= dist;
perp3x *= width;
perp3y *= width;
verts.push(p2x - (perp3x * r1), p2y - (perp3y * r1));
verts.push(p2x + (perp3x * r2), p2y + (perp3y * r2));
verts.push(p2x - (perp3x * r2 * r1), p2y - (perp3y * r1));
indexCount++;
}
else {
verts.push(p2x + ((px - p2x) * r1), p2y + ((py - p2y) * r1));
verts.push(p2x - ((px - p2x) * r2), p2y - ((py - p2y) * r2));
}
}
p1x = points[(length - 2) * 2];
p1y = points[((length - 2) * 2) + 1];
p2x = points[(length - 1) * 2];
p2y = points[((length - 1) * 2) + 1];
perpx = -(p1y - p2y);
perpy = p1x - p2x;
dist = Math.sqrt((perpx * perpx) + (perpy * perpy));
perpx /= dist;
perpy /= dist;
perpx *= width;
perpy *= width;
verts.push(p2x - (perpx * r1), p2y - (perpy * r1));
verts.push(p2x + (perpx * r2), p2y + (perpy * r2));
const indices = graphicsGeometry.indices;
// indices.push(indexStart);
for (let i = 0; i < indexCount - 2; ++i) {
indices.push(indexStart, indexStart + 1, indexStart + 2);
indexStart++;
}
}
/**
* Builds a line to draw using the gl.drawArrays(gl.LINES) method
*
* Ignored from docs since it is not directly exposed.
*
* @ignore
* @private
* @param {WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties
* @param {object} webGLData - an object containing all the WebGL-specific information to create this shape
*/
function buildNativeLine(graphicsData, graphicsGeometry) {
let i = 0;
const points = graphicsData.points || graphicsData.shape.points;
if (points.length === 0) return;
const verts = graphicsGeometry.points;
const indices = graphicsGeometry.indices;
const length = points.length / 2;
let indexStart = verts.length / 2;
// sort color
for (i = 1; i < length; i++) {
const p1x = points[(i - 1) * 2];
const p1y = points[((i - 1) * 2) + 1];
const p2x = points[i * 2];
const p2y = points[(i * 2) + 1];
verts.push(p1x, p1y);
verts.push(p2x, p2y);
indices.push(indexStart++, indexStart++);
}
}
...@@ -15,8 +15,7 @@ import Graphics from "../Graphics"; ...@@ -15,8 +15,7 @@ import Graphics from "../Graphics";
*/ */
export default { export default {
build(graphicsData:GraphicsData) build(graphicsData: GraphicsData) {
{
const rrectData = graphicsData.shape; const rrectData = graphicsData.shape;
const points = graphicsData.points; const points = graphicsData.points;
const x = rrectData.x; const x = rrectData.x;
...@@ -28,18 +27,43 @@ export default { ...@@ -28,18 +27,43 @@ export default {
points.length = 0; points.length = 0;
points.push(x, y + radius); // points.push(x, y + radius);
quadraticBezierCurve(x, y + height - radius, x, y + height, x + radius, y + height, points); // quadraticBezierCurve(x, y + height - radius, x, y + height, x + radius, y + height, points);
quadraticBezierCurve(x + width - radius, y + height, x + width, y + height, x + width, y + height - radius, points); // quadraticBezierCurve(x + width - radius, y + height, x + width, y + height, x + width, y + height - radius, points);
quadraticBezierCurve(x + width, y + radius, x + width, y, x + width - radius, y, points); // quadraticBezierCurve(x + width, y + radius, x + width, y, x + width - radius, y, points);
quadraticBezierCurve(x + radius, y, x, y, x, y + radius + 0.0000000001, points); // quadraticBezierCurve(x + radius, y, x, y, x, y + radius + 0.0000000001, points);
// this tiny number deals with the issue that occurs when points overlap and earcut fails to triangulate the item. // // this tiny number deals with the issue that occurs when points overlap and earcut fails to triangulate the item.
// TODO - fix this properly, this is not very elegant.. but it works for now. // // TODO - fix this properly, this is not very elegant.. but it works for now.
//20211212修改
if (!radius) {//顺时针
points.push(x, y,
x + width, y,
x + width, y + height,
x, y + height);
}
else {//顺时针
quadraticBezierCurve(x, y + radius,
x, y,
x + radius, y,
points);
quadraticBezierCurve(x + width - radius, y,
x + width, y,
x + width, y + radius,
points);
quadraticBezierCurve(x + width, y + height - radius,
x + width, y + height,
x + width - radius, y + height,
points);
quadraticBezierCurve(x + radius, y + height,
x, y + height,
x, y + height - radius,
points);
}
}, },
triangulate(graphicsData:GraphicsData, graphicsGeometry:Graphics) triangulate(graphicsData: GraphicsData, graphicsGeometry: Graphics) {
{
const points = graphicsData.points; const points = graphicsData.points;
const verts = graphicsGeometry.verts; const verts = graphicsGeometry.verts;
...@@ -49,8 +73,7 @@ export default { ...@@ -49,8 +73,7 @@ export default {
const triangles = earcut(points, null, 2); const triangles = earcut(points, null, 2);
for (let i = 0, j = triangles.length; i < j; i += 3) for (let i = 0, j = triangles.length; i < j; i += 3) {
{
indices.push(triangles[i] + vecPos); indices.push(triangles[i] + vecPos);
// indices.push(triangles[i] + vecPos); // indices.push(triangles[i] + vecPos);
indices.push(triangles[i + 1] + vecPos); indices.push(triangles[i + 1] + vecPos);
...@@ -58,8 +81,7 @@ export default { ...@@ -58,8 +81,7 @@ export default {
indices.push(triangles[i + 2] + vecPos); indices.push(triangles[i + 2] + vecPos);
} }
for (let i = 0, j = points.length; i < j; i++) for (let i = 0, j = points.length; i < j; i++) {
{
verts.push(points[i], points[++i]); verts.push(points[i], points[++i]);
} }
}, },
...@@ -78,8 +100,7 @@ export default { ...@@ -78,8 +100,7 @@ export default {
* @return {number} the result * @return {number} the result
* *
*/ */
function getPt(n1, n2, perc) function getPt(n1, n2, perc) {
{
const diff = n2 - n1; const diff = n2 - n1;
return n1 + (diff * perc); return n1 + (diff * perc);
...@@ -102,8 +123,7 @@ function getPt(n1, n2, perc) ...@@ -102,8 +123,7 @@ function getPt(n1, n2, perc)
* @param {number[]} [out=[]] - The output array to add points into. If not passed, a new array is created. * @param {number[]} [out=[]] - The output array to add points into. If not passed, a new array is created.
* @return {number[]} an array of points * @return {number[]} an array of points
*/ */
function quadraticBezierCurve(fromX, fromY, cpX, cpY, toX, toY, out = []) function quadraticBezierCurve(fromX, fromY, cpX, cpY, toX, toY, out = []) {
{
const n = 20; const n = 20;
const points = out; const points = out;
...@@ -114,8 +134,7 @@ function quadraticBezierCurve(fromX, fromY, cpX, cpY, toX, toY, out = []) ...@@ -114,8 +134,7 @@ function quadraticBezierCurve(fromX, fromY, cpX, cpY, toX, toY, out = [])
let x = 0; let x = 0;
let y = 0; let y = 0;
for (let i = 0, j = 0; i <= n; ++i) for (let i = 0, j = 0; i <= n; ++i) {
{
j = i / n; j = i / n;
// The Green Line // The Green Line
...@@ -128,6 +147,10 @@ function quadraticBezierCurve(fromX, fromY, cpX, cpY, toX, toY, out = []) ...@@ -128,6 +147,10 @@ function quadraticBezierCurve(fromX, fromY, cpX, cpY, toX, toY, out = [])
x = getPt(xa, xb, j); x = getPt(xa, xb, j);
y = getPt(ya, yb, j); y = getPt(ya, yb, j);
if (i === 0 && points[points.length - 2] === x && points[points.length - 1] === y) {
continue;
}
points.push(x, y); points.push(x, y);
} }
......
...@@ -70,18 +70,18 @@ export default class Polygon { ...@@ -70,18 +70,18 @@ export default class Polygon {
return new Polygon(this.points.slice()); return new Polygon(this.points.slice());
} }
/** // /**
* Closes the polygon, adding points if necessary. // * Closes the polygon, adding points if necessary.
* // *
*/ // */
close() { // close() {
const points = this.points; // const points = this.points;
// close the poly if the value is true! // // close the poly if the value is true!
if (points[0] !== points[points.length - 2] || points[1] !== points[points.length - 1]) { // if (points[0] !== points[points.length - 2] || points[1] !== points[points.length - 1]) {
points.push(points[0], points[1]); // points.push(points[0], points[1]);
} // }
} // }
/** /**
* Checks whether the x and y coordinates passed to this function are contained within this polygon * Checks whether the x and y coordinates passed to this function are contained within this polygon
......
...@@ -46,8 +46,8 @@ export default class RoundedRectangle { ...@@ -46,8 +46,8 @@ export default class RoundedRectangle {
//大于max取max //大于max取max
radius = radius > max ? max : radius; radius = radius > max ? max : radius;
//等于最大圆角时额外处理下,否则有点重合 // //等于最大圆角时额外处理下,否则有点重合
if (radius == max) radius -= 0.0000000001 // if (radius == max) radius -= 0.0000000001
this.radius = radius; this.radius = radius;
......
import FillStyle from './FillStyle'; import FillStyle from './FillStyle';
import { LINE_ALIGNMENT } from '../../const'; import { LINE_ALIGNMENT, LINE_CAP, LINE_JOIN } from '../../const';
/** /**
* 图形的画线模式 * 图形的画线模式
...@@ -18,16 +18,30 @@ export default class LineStyle extends FillStyle { ...@@ -18,16 +18,30 @@ export default class LineStyle extends FillStyle {
width: number; width: number;
/** /**
* 线的对齐方式 * 线的对齐方式
* 默认LINE_ALIGNMENT.middle 0.5 * @default LINE_ALIGNMENT.middle 0.5
*/ */
alignment: LINE_ALIGNMENT; alignment: LINE_ALIGNMENT;
/**
* Line cap style.
* @default LINE_CAP.BUTT
*/
cap = LINE_CAP.BUTT;
/**
* Line join style.
* @default LINE_JOIN.MITER
*/
join = LINE_JOIN.MITER;
/**
* Miter limit.
*/
miterLimit = 10;
/** /**
* Clones the object * Clones the object
* *
* @return {LineStyle} * @return {LineStyle}
*/ */
clone():LineStyle { clone(): LineStyle {
const obj:LineStyle = new LineStyle(); const obj: LineStyle = new LineStyle();
obj.color = this.color; obj.color = this.color;
obj.alpha = this.alpha; obj.alpha = this.alpha;
obj.texture = this.texture; obj.texture = this.texture;
...@@ -36,6 +50,9 @@ export default class LineStyle extends FillStyle { ...@@ -36,6 +50,9 @@ export default class LineStyle extends FillStyle {
obj.width = this.width; obj.width = this.width;
obj.alignment = this.alignment; obj.alignment = this.alignment;
obj.native = this.native; obj.native = this.native;
obj.cap = this.cap;
obj.join = this.join;
obj.miterLimit = this.miterLimit;
return obj; return obj;
} }
/** /**
...@@ -48,5 +65,8 @@ export default class LineStyle extends FillStyle { ...@@ -48,5 +65,8 @@ export default class LineStyle extends FillStyle {
this.width = 0; this.width = 0;
this.alignment = 0.5; this.alignment = 0.5;
this.native = false; this.native = false;
this.cap = LINE_CAP.BUTT;
this.join = LINE_JOIN.MITER;
this.miterLimit = 10;
} }
} }
...@@ -144,4 +144,27 @@ export function bezierCurveLength( ...@@ -144,4 +144,27 @@ export function bezierCurveLength(
} }
return result; return result;
} }
\ No newline at end of file /**
* 判断一系列点的顺逆时针方向,以后有需要用吧
* @see {@link https://stackoverflow.com/questions/1165647}
* 1、向量首尾相连,计算所有相邻向量的叉乘的和,正号逆时针(右手定则)
* 2、以(0,0)为原点,每两个点作为两个向量,叉乘的和就是面积的两倍,符号表示方向(同1)
* 3、下面这种 (x2 − x1)(y2 + y1).看不懂原理,但是计算过是一致的,正号顺时针(与上两种相反)
* @param points 一维点序列,比如[0,0,1,1,0,2]
* @param closed 是否连回起始点
* @returns true表示顺时针,false表示逆时针
*/
export function isPointsClockwise(points: ArrayLike<number>, closed: boolean = false): boolean {
let sum = 0;
for (let i = 0; i < points.length - 2; i += 2) {
sum += (points[i + 2] - points[i]) * (points[i + 3] + points[i + 1]);
}
//是否连回原点
if (closed) sum += (points[0] - points[points.length - 2]) * (points[1] + points[points.length - 1]);
// return sum > 0;
//当前2d坐标系,y轴朝下为正,所以判断反下,
return sum < 0;
}
...@@ -32,7 +32,7 @@ export class ObservablePoint extends HashObject { ...@@ -32,7 +32,7 @@ export class ObservablePoint extends HashObject {
* @param {number} [x=0] * @param {number} [x=0]
* @param {number} [y=0] * @param {number} [y=0]
*/ */
set(x: number = 0, y: number = x) { set(x: number, y: number) {
const _x = x || 0; const _x = x || 0;
const _y = y || 0; const _y = y || 0;
......
...@@ -50,8 +50,12 @@ export class CanvasGraphicsRenderer { ...@@ -50,8 +50,12 @@ export class CanvasGraphicsRenderer {
const lineColor = lineStyle.color; const lineColor = lineStyle.color;
context.lineWidth = lineStyle.width; context.lineWidth = lineStyle.width;
//新增3个属性,还有个alignment不晓得应该咋搞好,TODO
context.lineCap = lineStyle.cap;
context.lineJoin = lineStyle.join;
context.miterLimit = lineStyle.miterLimit;
var ccw = true; var ccw = true;//记录画洞的路径方向,填充默认用顺时针,所以画洞用逆时针
if (data.type === SHAPES.POLY) { if (data.type === SHAPES.POLY) {
//必须每次清空子路径列表,因为每个data视为独立 //必须每次清空子路径列表,因为每个data视为独立
...@@ -124,7 +128,7 @@ export class CanvasGraphicsRenderer { ...@@ -124,7 +128,7 @@ export class CanvasGraphicsRenderer {
const height = shape.height; const height = shape.height;
let radius = shape.radius; let radius = shape.radius;
const maxRadius = Math.min(width, height) / 2 | 0; const maxRadius = Math.min(width, height) / 2 //| 0;
radius = radius > maxRadius ? maxRadius : radius; radius = radius > maxRadius ? maxRadius : radius;
......
import {CanvasRenderer} from '../CanvasRenderer'; import { CanvasRenderer } from '../CanvasRenderer';
import { SCALE_MODES, BLEND_MODES } from '../../const'; import { SCALE_MODES, BLEND_MODES } from '../../const';
import { Matrix, GroupD8 } from '../../math'; import { Matrix, GroupD8 } from '../../math';
import Sprite from '../../display/Sprite'; import Sprite from '../../display/Sprite';
...@@ -58,7 +58,7 @@ export default class CanvasSpriteRenderer { ...@@ -58,7 +58,7 @@ export default class CanvasSpriteRenderer {
// // 如果遇到性能问题,先禁掉 // // 如果遇到性能问题,先禁掉
// renderer.context[renderer.smoothProperty] = smoothingEnabled; // renderer.context[renderer.smoothProperty] = smoothingEnabled;
// } // }
if (sprite._anchorTexture) { if (sprite._anchorTexture) {//sprite
if (texture.trim) { if (texture.trim) {
dx = (texture.trim.width / 2) + texture.trim.x - (sprite._anchorTexture.x * texture.orig.width); dx = (texture.trim.width / 2) + texture.trim.x - (sprite._anchorTexture.x * texture.orig.width);
dy = (texture.trim.height / 2) + texture.trim.y - (sprite._anchorTexture.y * texture.orig.height); dy = (texture.trim.height / 2) + texture.trim.y - (sprite._anchorTexture.y * texture.orig.height);
...@@ -79,10 +79,14 @@ export default class CanvasSpriteRenderer { ...@@ -79,10 +79,14 @@ export default class CanvasSpriteRenderer {
dx -= width / 2; dx -= width / 2;
dy -= height / 2; dy -= height / 2;
} else { } else if (sprite.instanceType == "Graphics") {//graphics
dx = sprite["offsetX"] || 0; // dx = sprite["offsetX"] || 0;
dy = sprite["offsetY"] || 0; // dy = sprite["offsetY"] || 0;
// console.log(sprite["offsetX"]) // console.log(sprite["offsetX"])
//不用offset或_offset,在Graphics里删除了,直接用_localBoundsSelf
const { x, y } = sprite._localBoundsSelf;
dx = x;
dy = y;
} }
renderer.context.setTransform( renderer.context.setTransform(
...@@ -143,8 +147,8 @@ export default class CanvasSpriteRenderer { ...@@ -143,8 +147,8 @@ export default class CanvasSpriteRenderer {
); );
} }
//如果处理过outerBlend //如果处理过outerBlend
if (outerBlend) renderer.context.restore(); if (outerBlend) renderer.context.restore();
//以防万一,设置一次 //以防万一,设置一次
renderer.setBlendMode(BLEND_MODES.NORMAL); renderer.setBlendMode(BLEND_MODES.NORMAL);
} }
......
...@@ -12,7 +12,7 @@ const padding = 10; ...@@ -12,7 +12,7 @@ const padding = 10;
* 到时有离屏canvas再修改,现在离屏canvasios有问题,且文本模糊 * 到时有离屏canvas再修改,现在离屏canvasios有问题,且文本模糊
* 继承Sprite,暂时发现,只需要切换bitmap和Sprite,TextField永远都是最新的,到时替换 * 继承Sprite,暂时发现,只需要切换bitmap和Sprite,TextField永远都是最新的,到时替换
* 动态文本类,有时需要在canvas里有一个动态文本,能根据我们的显示内容来改变 * 动态文本类,有时需要在canvas里有一个动态文本,能根据我们的显示内容来改变
* @class TextFieldCon * @class TextField
* @extends DisplayObject * @extends DisplayObject
* @since 1.0.0 * @since 1.0.0
* @public * @public
...@@ -21,15 +21,15 @@ export class TextField extends Sprite { ...@@ -21,15 +21,15 @@ export class TextField extends Sprite {
private static shareCanvas: HTMLCanvasElement; private static shareCanvas: HTMLCanvasElement;
private static shareContext: CanvasRenderingContext2D; private static shareContext: CanvasRenderingContext2D;
canvas: HTMLCanvasElement; private canvas: HTMLCanvasElement;
context: CanvasRenderingContext2D; private context: CanvasRenderingContext2D;
/** /**
* 与其他类不同,用了Boolean,再考虑 * 与其他类不同,用了Boolean,再考虑
*/ */
dirty: boolean; private dirty: boolean;
offsetX: number; // offsetX: number;
offsetY: number; // offsetY: number;
constructor() { constructor() {
super(); super();
this._instanceType = "TextField"; this._instanceType = "TextField";
...@@ -56,7 +56,7 @@ export class TextField extends Sprite { ...@@ -56,7 +56,7 @@ export class TextField extends Sprite {
// TextField.shareContext = TextField.shareCanvas.getContext("2d"); // TextField.shareContext = TextField.shareCanvas.getContext("2d");
// } // }
// var baseTexture = new BaseTexture({ // var baseTexture = new BaseTexture({
// data: [], // _data: [],
// width: 0, // width: 0,
// height: 0, // height: 0,
// type: "text", // type: "text",
...@@ -636,9 +636,9 @@ export class TextField extends Sprite { ...@@ -636,9 +636,9 @@ export class TextField extends Sprite {
} }
ctx.fillText(realLines[i], ox, upY + i * lineH + oy/*, maxW*/);//考虑去掉这个maxW ctx.fillText(realLines[i], ox, upY + i * lineH + oy/*, maxW*/);//考虑去掉这个maxW
} }
//offset用_anchorTexture代替 // //offset用_anchorTexture代替
s.offsetX = -padding; // s.offsetX = -padding;
s.offsetY = -padding; // s.offsetY = -padding;
// console.log(can) // console.log(can)
this.anchorTexture = { x: (padding + 0.5) / canWidth, y: padding / canHeight } this.anchorTexture = { x: (padding + 0.5) / canWidth, y: padding / canHeight }
// if (osType == "ios") { // if (osType == "ios") {
...@@ -648,7 +648,7 @@ export class TextField extends Sprite { ...@@ -648,7 +648,7 @@ export class TextField extends Sprite {
// } else { // } else {
// var imgData = ctx.getImageData(0, 0, canWidth, canHeight) // var imgData = ctx.getImageData(0, 0, canWidth, canHeight)
// var data = { // var data = {
// data: new Uint8Array(imgData.data), // _data: new Uint8Array(imgData.data),
// width: canWidth, // width: canWidth,
// height: canHeight, // height: canHeight,
// type: "text", // type: "text",
......
...@@ -73,13 +73,36 @@ ...@@ -73,13 +73,36 @@
circle.x = 200; circle.x = 200;
circle.y = 200; circle.y = 200;
circle.clear(); circle.clear();
circle.lineStyle(50, '0xff0000',1,0.5); circle.lineStyle(50, '0xff0000',1,1);
// circle.beginFill('0xffffff', 0); // circle.beginFill('0xffffff', 0);
//画圆,注意,这里画圆依然是基于circle的坐标来画的,而不是舞台 //画圆,注意,这里画圆依然是基于circle的坐标来画的,而不是舞台
circle.drawCircle(0, 0, 80); circle.drawCircle(0, 0, 80);
circle.endFill(); circle.endFill();
// circle.moveTo(0,0).lineTo(0,100) // circle.moveTo(0,0).lineTo(0,100)
circle.updateLocalBoundsSelf()
console.log(circle._localBoundsSelf) console.log(circle._localBoundsSelf)
var line =stage.addChild( new FYGE.Graphics());
// line.beginFill(0)
// line.lineStyle(30, '0xff0000',1,1);
line.beginStroke(0xff0000,30,"square","round",10,1,1)
line.moveTo(30,530)
line.lineTo(120,560)
line.lineTo(60,660)
line.lineTo(200,660)
// line.lineTo(30,530)
// line.closePath()
setTimeout(()=>{
console.log(line.verts)
console.log(line.indices)
},1000)
var gg = stage.addChild( new FYGE.Graphics())
gg.beginFill(0xff0000)
.lineStyle(10,0xffff00,1,1)
.drawRoundedRect(300,300,300,300,150)
}, this); }, this);
//循环 //循环
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment