<div>
<div>
<span>相似比常数</span>
<input
type="range"
id="tension"
min="-1"
max="2"
step=".1"
value=".5"
/>
Tension <span id="tensionvalue">(0.5)</span>
</div>
<div>
<span>是否使用距离比例 d1/(d1+d2)</span>
<label><input type="checkbox" id="useRate" /> 是否使用距离比例</label>
</div>
</div>
<div>
<canvas id="canvas"></canvas>
</div>
* {
padding: 0;
margin: 0;
}
let isCtrl = false;
function $(id) {
return document.getElementById(id);
}
function update() {
$("tensionvalue").innerHTML = "(" + $("tension").value + ")";
drawLine2();
}
$("useRate").onchange = $("tension").onchange = update;
let type = "WebGL";
if (!PIXI.utils.isWebGLSupported()) {
type = "canvas";
}
PIXI.utils.sayHello(type);
//Create a Pixi Application
let app = new PIXI.Application({
width: 800, // default: 800
height: 800, // default: 600
antialias: true, // default: false
transparent: false, // default: false
resolution: 1, // default: 1
backgroundColor: 0x061639,
view: document.getElementById("canvas"),
});
document.body.appendChild(app.view);
const canvas = app.view;
var arr = [];
const r = 12;
let currentPoint;
canvas.addEventListener("click", function (event) {
mousePosFun(canvas, event);
});
function drawLine(from, to) {
drawLine2();
}
function getMiddle(from, to) {
return {
pos: {
x: (from.pos.x + to.pos.x) / 2,
y: (from.pos.y + to.pos.y) / 2,
},
};
}
function drawBaseLine(from, to) {
line = new PIXI.Graphics();
line.lineStyle(4, 0x1a7af8, 1);
line.moveTo(from.x, from.y);
line.lineTo(to.x, to.y);
app.stage.addChild(line);
ss.push(line);
}
// 数组的两个点的构成的直角三角形的[w,h]
function va(arr, i, j) {
return [arr[2 * j] - arr[2 * i], arr[2 * j + 1] - arr[2 * i + 1]];
}
// 计算arr数组的i和j两个点之间的距离
function distance(arr, i, j) {
return Math.sqrt(
Math.pow(arr[2 * i] - arr[2 * j], 2) +
Math.pow(arr[2 * i + 1] - arr[2 * j + 1], 2)
);
}
function controlPoints(x1, y1, x2, y2, x3, y3) {
var t = Number($("tension").value);
// 返回 w 和 h=>[w,h]
var v = va(arguments, 0, 2);
var d01 = distance(arguments, 0, 1);
var d12 = distance(arguments, 1, 2);
// 带入距离比例
var d012 = d01 + d12;
let s = t;
if ($("useRate").checked) {
s = (t * d01) / d012;
}
return [x2 - v[0] * s, y2 - v[1] * s, x2 + v[0] * s, y2 + v[1] * s];
}
let ss = [];
let pts = [];
function drawLine2() {
// 将画布的线条全部清空
for (let ii = 0; ii < ss.length; ii++) {
const bezier = ss[ii];
app.stage.removeChild(bezier);
}
ss = [];
pts = [];
// 将对象的数组转换为点的一维数组形式
arr
.map((i) => i.pos)
.forEach((item) => {
pts.push(item.x);
pts.push(item.y);
});
cps = []; // 控制点的位置
// 获取控制点的位置
for (var i = 0; i < pts.length - 2; i += 1) {
cps = cps.concat(
controlPoints(
pts[2 * i],
pts[2 * i + 1],
pts[2 * i + 2],
pts[2 * i + 3],
pts[2 * i + 4],
pts[2 * i + 5]
)
);
}
let start = arr[0];
// 两个点直接画直线
if (arr.length === 2) {
drawBaseLine(start.pos, arr[1].pos);
}
// 多个点
console.log("pts", pts, "cps", cps);
let end;
let control;
let len = arr.length;
if (arr.length >= 3) {
start = arr[0];
end = arr[1];
// 开始是一跳二次贝赛尔曲线
var bezier = new PIXI.Graphics();
bezier.lineStyle(4, 0x1a7af8, 1);
bezier.moveTo(start.pos.x, start.pos.y);
bezier.quadraticCurveTo(cps[0], cps[1], pts[2], pts[3]);
bezier.endFill();
start = end;
app.stage.addChild(bezier);
ss.push(bezier);
// 中间的部分是三次贝赛尔曲线
for (var i = 2; i < len - 1; i += 1) {
start = end;
var bezier = new PIXI.Graphics();
bezier.lineStyle(4, 0x1a7af8, 1);
bezier.moveTo(start.pos.x, start.pos.y);
bezier.bezierCurveTo(
cps[(2 * (i - 1) - 1) * 2],
cps[(2 * (i - 1) - 1) * 2 + 1],
cps[2 * (i - 1) * 2],
cps[2 * (i - 1) * 2 + 1],
pts[i * 2],
pts[i * 2 + 1]
);
bezier.endFill();
end = arr[i];
app.stage.addChild(bezier);
ss.push(bezier);
}
start = end;
var bezier = new PIXI.Graphics();
bezier.lineStyle(4, 0x1a7af8, 1);
bezier.moveTo(start.pos.x, start.pos.y);
bezier.quadraticCurveTo(
cps[(2 * (i - 1) - 1) * 2],
cps[(2 * (i - 1) - 1) * 2 + 1],
pts[i * 2],
pts[i * 2 + 1]
);
bezier.endFill();
app.stage.addChild(bezier);
ss.push(bezier);
}
}
function drawPoint(x, y, first, last) {
let circle = new PIXI.Graphics();
circle.beginFill(0x9966ff);
circle.drawCircle(0, 0, r);
circle.endFill();
circle.x = x;
circle.y = y;
app.stage.addChild(circle);
return circle;
}
function mousePosFun(canvas, event, manuel) {
var rect = canvas.getBoundingClientRect();
var x, y;
if (!manuel) {
// 获取坐标
x = event.clientX - rect.left * (canvas.width / rect.width);
y = event.clientY - rect.top * (canvas.height / rect.height);
} else {
x = manuel.x;
y = manuel.y;
}
let circle = drawPoint(x, y, arr.length === 0);
let line;
const data = {
pos: { x, y }, //点的位置
circle, // 圆
line, //线
id: Math.random(),
};
// 看看是否存在前面一项
arr.push(data);
drawLine();
}
[
{ x: 100, y: 100 },
{ x: 400, y: 100 },
{ x: 400, y: 400 },
{ x: 100, y: 400 },
].forEach((item) => {
mousePosFun(canvas, {}, item);
});
This Pen doesn't use any external CSS resources.