蓝紫™
DDZEB 完全自主知识产权图形图像开发平台
开放源码 免费使用 在线运行
二维函数及图形渲染,数学探索和演示动画的好帮手。
文件语言大小版本开发者最后更新
lands/curve productionJavaScript11.7KBv1.0.0YB2024-10-16查看
lands/curve source codeJavaScript29.1KBv1.0.0YB2024-10-16查看
一、简要介绍 二、接口方法三、接口属性四、后记 一、简要介绍

纯 JS 的二维渲染因为其绘制机制容易理解,可以快速绘制各种矢量图形。curve 渲染引擎是对传统 CanvasRenderingContext2D 的封装,但是坐标系统做了调整,不再是 Y 轴向下,而是跟我们平常的习惯一致,X 轴从左向右,而 Y 轴从下往上。所有的渲染操作都是在这个世界坐标系下完成,我们不再关心画布像素坐标。

蓝紫 curve 引擎渲染曲线:Hello Curve Animated
蓝紫 curve 引擎渲染文字:文字动画
二、接口方法

使用 curve 引擎的时候,options 只有一个参数:alpha,缺省为 true,表示画布透明。我们也可以将其设置为 false,不过基本上没必要。

const canvas = await Lan.curve(900, 600, {
  alpha : false,
});

具体例子可参考 Canvas Texture。在我们将画布绑定 curve 引擎之后,所有的接口都将通过 canvas 本身进行调用。接口大概分两类,一是计算类的,二是渲染类的。所有渲染类型的操作,基本接口形式均是:

api_name(param1, param2, ..., options = {})

其中,api_name 为接口名称,param1、param2 等为必要的参数列表,options 为配置项。所有渲染操作都支持的配置项包括:

2.1、view(x0, x1, y)

curve 有一个世界坐标,我们的渲染操作全部都是在世界坐标系统中进行。curve 的世界坐标必须是 x 方向从左到右而 y 方向是从下到上。我们使用 view 函数设定世界坐标系统,或者叫视口坐标系统。缺省的视口坐标位于画布中央,我们可以通过 x0 以及 x1 来设定 x 方向的范围,垂直方向上通过 y 参数来调整位置。比如:

p.view(-5, 15, -3);

需要注意的是,如果视口区域设置得太小,渲染文字的时候可能引起浏览器兼容问题,只有 Chrome 浏览器在处理上是没问题的。

2.2、clear(options)

清除数据,可以使用 x0、x1、y0、y1 指定区域,缺省为整个画布视口区域。另外,通过 fill 可以指定填充色。

p.clear({fill:'yellow'});
2.3、grid(options)

网格渲染,通过网格参数 options 修改样式:

p.grid({
  alpha:.2, blend:'source-over', filter:'none',
  margin:.5, line:.05, dash:[.3, .1], stroke:'red',
  size:2, v:true, h:true,
});

其中,size 为网格的格子大小。v 和 h 分别控制是否绘制垂直以及水平线条,缺省为 true。

2.4、axis(options)

绘制坐标轴,缺省的 x 及 y 方向的坐标轴为黑色线条,我们可以使用 options 参数调整样式:

p.axis({
  line:.05, stroke:'red',
});
2.5、func(f, options)

该函数进行二维函数的渲染,传入的参数 f 定义一个二维函数,比如 Math.sin(正弦函数),可选参数 options 指定渲染参数。比如:

p.func(Math.sin, {
  x0:-5, x1:5,
  stroke:'red', alpha:.4, line:.1, dash:[.5, .2],
});

缺省情况下,函数曲线连续连接,比如下面的锯齿波函数:

p.func(x => x - Math.floor(x));

如果我们不希望渲染垂直的连线,可以通过 options.dx 参数进行控制:

p.func(x => x - Math.floor(x), {dx:true});
2.6、line(x0, y0, x1, y1, options, extend0, extend1)

我们可以在图像中画一些直线段,options 参数可选:

p.line(1, -1, 7, -4, {
  stroke:'red', alpha:.6, line:.1, dash:[.5, .2],
});

另外,我们还可以通过 extend0、extend1 这两个参数绘制延长线,分别延长 (x0, y0) 以及 (x1, y1) 两个端点。当它们为 true 的时候,使用原样式延长。也可以使用 {color:'red'} 这样的参数形式指定延长线的样式。

p.line(-5, 3, 1, -1, {stroke:'red', line:.1}, {
  stroke:'blue', line:.05, dash:[.5, .2],
}, {
  stroke:'black', line:.05, len:5,
});
2.7、ray(x0, y0, dirX, dirY, options)

画射线,起点 (x0, y0),方向 (dirX, dirY),options 控制样式等:

p.ray(-3, -2, 4, 8, {
  alpha:.6,
  stroke:'red', line:.05, cap:'round', join:'round', 
  dash:[.4, .1], len:6
});

不指定 len 参数的时候,射线无限延长。

2.8、angle(x, y, dirX1, dirY1, dirX2, dirY2, options)

参数看起来有点多,不过还是好理解的,x 及 y 定出位置,dirX1 和 dirY1 定出起始角度,dirX2 和 dirY2 定出终止角度。

const dx1 = 1, dy1 = 0;
const dx2 = -.5, dy2 = 1;

canvas.angle(0, 0, dx1, dy1, dx2, dy2, {
  fill:'rgba(255,0,0,.2)',
  radius:.8, line:.05, stroke:'black',
});

canvas.ray(0, 0, dx1, dy1);
canvas.ray(0, 0, dx2, dy2);
2.9、hline(y, options)

画水平方向直线,options 参数可选:

p.hline(-2, {stroke:'red', alpha:.5, line:.1, dash:[.5, .2]});
2.10、vline(y, options)

画垂直方向直线,options 参数可选:

p.vline(-2, {stroke:'red', alpha:.5, line:.1, dash:[.5, .2]});
2.11、rect(x0, y0, x1, y1, options)

画矩形,options 参数可选:

p.rect(-3, -2, 4, 4, {
  alpha:.6,
  stroke:'red', line:.1, cap:'round', join:'round', 
  dash:[2, .3], fill:'yellow', round:0,
});
2.12、circle(x, y, options)

画圆,options 参数可选:

p.circle(3, -1, {
  alpha:.6,
  radius:4, a0:2, a1:5.6, fan:false,
  stroke:'red', line:.05, cap:'round', join:'round', 
  dash:[.4, .1], fill:'yellow',
});

参数 radius 可以是负值,比如,上面的代码将 radius 设置为 -4,绘制结果如下:

另外,参数 fan 用于控制是否绘制为扇形,比如,上面的代码如果将 fan 设置项去掉或者设置为 true,绘制出的图像如下:

如果要画椭圆,就将 radius 替换为 radiusX 以及 radiusY 两个参数,同时还可以指定 rotation 进行旋转:

p.circle(0, 0, {
  alpha:.6,
  radiusX:4, radiusY:2, rotation:1., a0:.9, a1:6, fan:false,
  stroke:'red', line:.05, cap:'round', join:'round', 
  dash:[.4, .1], fill:'yellow',
});
2.13、poly(points, options)

画多边形,其中 points 为点集,比如:[-1,0, 5,5, 0,4] 这样的数组。options 指定样式,该参数可选:

p.poly([-1,0, 5,5, 0,4], {
  alpha:.6, close:false,
  stroke:'red', line:.05, cap:'round', join:'round', 
  dash:[.4, .1], fill:'yellow',
});

其中 close 参数缺省为 true,表示图形闭合。

2.14、label(str, x, y, options)

画标签文字(单行),返回 Bounding Box:

var strip = p.pattern({type:'strip2', fact:.1});
var rect = p.label('Hello World', 3, 2, {
  font:'bold 2px serif', kerning:'none', spacing:'0px',
  fill:strip, stroke:'black', bg:'yellow',
  paddingX:.7, paddingY:.5,
});
p.rect(rect.l, rect.t, rect.r, rect.b, {stroke:'red'});

文字背景色 bg 缺省为画布背景色,当 bg == 'none' 时,没有背景色(相当于背景色透明)。

2.15、text(str, x, y, options)

渲染多行文本,返回 Bounding Box:

var rect = p.text('Brief Introduction to DDZEB Lands\n\n蓝紫(Lands)是由 DDZEB 完全自主开发出品的一款免费在线图形图像开发平台\n\n通过编写代码进行二维、三维图形图像的渲染及绘制', -4, 4, {
  font:'.5px arial', gap:.2, blank:.5,
  bg:'yellow', paddingX:1, paddingY:.5,
  fill:'#000', width:5,
});
p.rect(rect.l, rect.t, rect.r, rect.b, {stroke:'red'});
2.16、draw(image, x, y, options)

将图像或者视频等画到以 x 和 y 为中心的位置上。options 包括:

const p = await Lan.curve(1200, 800);
p.view(-1000, 1000);
p.clear({fill:'#555'});

const media = (await Lan.import('media')).media();
const image = await media.image('I2');

const path = new Path2D();
path.arc(0, 0, 500, 0, 2 * Math.PI);

p.draw(image, 0, 0, {
  clip:path, scale:0.5, repeat:'repeat',
});
p.axis();
2.17、pattern(options)

生成填充样式,比如为多边形画阴影线:

var s = p.pattern({
  type:'strip1',
  fact:.05, bg:[255,255,0,128], fg:[255,0,0,128],
});
p.poly([
  -3,2, 6,1, 1,-4
], {fill:s});

除了使用 type 选择内置的样式以外,还可以使用图片作为样式:

const image = await Lan.image('T21');
await Lan.font('baby', 'F1');
const pattern = p.pattern({image:image, scale:.1});
p.label('Hello Curve', 0, 0, {
  font:'bold 3px baby', fill:pattern,
  stroke:'gray', line:.04, dash:[.3],
  filter:'drop-shadow(5px 5px 6px black)',
});
2.18、linearGradient(x0, y0, x1, y1, stops)

线性渐变,可用于填充以及线条颜色。

const canvas = await Lan.curve();
const gra = canvas.linearGradient(-500, -100, 500, 100, [
  0, '#ff727d', 0.5, '#000', 1, '#72b3ff',
]);
canvas.clear({fill:gra});
2.19、radialGradient(x, y, r0, r1, stops)

辐射线性渐变,可用于填充以及线条颜色。

const canvas = await Lan.curve();
const gra = canvas.radialGradient(-100, 0, 0, 500, [
  0, '#ff727d', 0.5, '#000', 1, '#72b3ff',
]);
canvas.clear({fill:gra});
2.20、conicGradient(x, y, startAngle, stops)

辐射线性渐变,可用于填充以及线条颜色。

const canvas = await Lan.curve();
const gra = canvas.conicGradient(0, 0, 0, [
  0, '#ff727d', 0.5, '#000', 1, '#72b3ff',
]);
canvas.clear({fill:gra});
2.21、getput

这两个函数的主要目的是加速动画渲染,通过 get 函数可以取得画布图像,通过 put 可以将图像写入画布,具体使用方法请参考蓝紫示例程序:Wave Fading

2.22、point(pixelX, pixelY)

从画布空间将像素坐标映射到世界空间得到世界坐标,返回 [pointX, pointY] 数组。当要处理鼠标事件的时候,这个函数就很方便。蓝紫辅助工具 Julia 集合常数 就用到了这个函数进行坐标映射。

3D Geometries
蓝紫辅助工具:Julia 集合常数
2.23、pixel(pointX, pointY)

该函数将世界坐标映射到画布像素坐标,返回数组 [pixelX, pixelY]。

三、接口属性 3.1、CONTEXT

渲染上下文,CanvasRenderingContext2D。当现有接口方法满足不了要求的时候,我们可以通过渲染上下文进行手动扩展。

3.2、x0、x1、y0、y1

视口区域属性,其中 x0 < x1,y0 < y1。

3.3、pointSize、pixelSize

这两个属性代表了世界坐标与画布像素坐标之间的比例(scale)关系,其中 pointSize 代表世界坐标中的 1 在像素空间中覆盖多少个像素,而 pixelSize 代表像素空间中一个像素在世界空间中的大小。

四、后记

这个接口文档看起来挺复杂,实际上使用起来很简单。有了这个工具,我们再也不需要寻找第三方平台。可以画函数曲线的第三方平台其实很多,但都太过复杂,鼠标点来点去,半天还没搞定。而实际上我们有时候就只是希望给一个函数,工具帮忙画出来就是了,这就是 curve 渲染引擎的核心诉求。除了常规的数学绘图,也可进行艺术创作,除了二维渲染,也可以画三维,比如:

3D Geometries

目前,蓝紫 curve.js 开发库已经完全可以满足二维函数的设计和渲染工作,我们将暂时停止开发新的功能。最后,送给大家一个特别的波形信号:

Strange Wave
蓝紫程序源代码:Strange Wave