var Point = (function() {
function Point(x, y, connectedTo) {
if (connectedTo === void 0) { connectedTo = []; }
this.x = x;
this.y = y;
this.connectedTo = connectedTo;
}
return Point;
}());
var Polygon = (function() {
function Polygon(points, constrains) {
if (constrains === void 0) { constrains = []; }
this.points = points;
this.constrains = constrains;
}
return Polygon;
}());
var Sketch = (function() {
function Sketch(polygons, canvas) {
if (polygons === void 0) { polygons = []; }
if (canvas === void 0) { canvas = document.body.appendChild(document.createElement("canvas")); }
this.polygons = polygons;
this.canvas = canvas;
this.canvas.width = 1000;
this.canvas.height = 1000;
this.ctx = this.canvas.getContext("2d");
this.ctx.fillStyle = "#0971CE";
this.ctx.strokeStyle = "white";
this.canvas.onmousedown = this.clickHandler.bind(this);
this.canvas.onmouseup = this.clickHandler.bind(this);
this.canvas.onmousemove = this.clickHandler.bind(this);
requestAnimationFrame(this.draw.bind(this));
}
Sketch.prototype.clickHandler = function (evt) {
if (evt.type == "mousedown") {
if (this.selectedPoint != void 0) {
this.selectedPoint = null;
}
else {
var score = null;
var best = null;
for (var p = 0; p < this.polygons.length; p++) {
var polygon = this.polygons[p];
for (var pi = 0; pi < polygon.points.length; pi++) {
var point = polygon.points[pi];
var dist = Math.abs(point.x - evt.offsetX) + Math.abs(point.y - evt.offsetY);
if (score == null ? true : dist < score) {
score = dist;
best = point;
}
}
}
this.selectedPoint = best;
}
}
if (evt.type == "mousemove" && this.selectedPoint != void 0) {
this.selectedPoint.x = Math.round(evt.offsetX/5) * 5;
this.selectedPoint.y = Math.round(evt.offsetY/5) * 5;
for (var pi = 0; pi < this.polygons.length; pi++) {
var polygon = this.polygons[pi];
if (polygon.points.indexOf(this.selectedPoint) < 0) {
continue;
}
for (var pa = 0; pa < polygon.constrains.length; pa++) {
var constrain = polygon.constrains[pa];
if (constrain.a == this.selectedPoint || constrain.b == this.selectedPoint) {
constrain.a[constrain.key] = this.selectedPoint[constrain.key];
constrain.b[constrain.key] = this.selectedPoint[constrain.key];
if (constrain.offset != void 0) {
if (constrain.a == this.selectedPoint) {
constrain.b[constrain.key] += constrain.offset;
}
else {
constrain.a[constrain.key] -= constrain.offset;
}
}
}
}
}
}
requestAnimationFrame(this.draw.bind(this));
};
Sketch.prototype.draw = function() {
var ctx = this.ctx;
//clear
ctx.fillStyle = "#0971CE";
ctx.fillRect(0, 0, 1000, 1000);
//grid
ctx.strokeStyle = "rgba(255,255,255,0.25)";
for (var x = 0; x <= this.canvas.width; x += 5) {
ctx.beginPath();
ctx.moveTo(x, -1);
ctx.lineTo(x, this.canvas.height);
ctx.stroke();
ctx.closePath();
}
for (var y = 0; y <= this.canvas.height; y += 5) {
ctx.beginPath();
ctx.moveTo(-1, y);
ctx.lineTo(this.canvas.width, y);
ctx.stroke();
ctx.closePath();
}
ctx.strokeStyle = "white";
ctx.fillStyle = "white";
//shapes
for (var i = 0; i < this.polygons.length; i++) {
var polygon = this.polygons[i];
for (var pa = 0; pa < polygon.points.length; pa++) {
var pointa = polygon.points[pa];
if (pointa == this.selectedPoint) {
ctx.beginPath();
ctx.fillRect(pointa.x - 2, pointa.y - 2, 4, 4);
ctx.closePath();
}
ctx.beginPath();
for (var pb = 0; pb < pointa.connectedTo.length; pb++) {
var pointb = pointa.connectedTo[pb];
if (polygon.points.indexOf(pointb) < pa) {
continue;
}
ctx.moveTo(pointa.x, pointa.y);
ctx.lineTo(pointb.x, pointb.y);
}
ctx.stroke();
ctx.closePath();
}
}
};
return Sketch;
}());
//==Test==
//Build polygon 1 (House)
var poly1 = new Polygon([
new Point(10, 10),
new Point(80, 10),
new Point(80, 45),
new Point(130, 45),
new Point(130, 95),
new Point(80, 95),
new Point(80, 135),
new Point(10, 135),
]);
//Connect dots
for (var x = 0; x < poly1.points.length; x++) {
var a = poly1.points[x];
var b = poly1.points[(x + 1) % poly1.points.length];
a.connectedTo.push(b);
b.connectedTo.push(a);
}
//Setup constrains
for (var x = 0; x < poly1.points.length; x++) {
var a = poly1.points[x];
var b = poly1.points[(x + 1) % poly1.points.length];
poly1.constrains.push({ a: a, b: b, key: x % 2 == 1 ? 'x' : 'y' });
}
poly1.constrains.push({ a: poly1.points[1], b: poly1.points[5], key: 'x' }, { a: poly1.points[2], b: poly1.points[5], key: 'x' }, { a: poly1.points[1], b: poly1.points[6], key: 'x' }, { a: poly1.points[2], b: poly1.points[6], key: 'x' });
//Build polygon 2 (Triangle)
var poly2 = new Polygon([
new Point(250, 250),
new Point(300, 300),
new Point(200, 300),
]);
//Connect dots
for (var x = 0; x < poly2.points.length; x++) {
var a = poly2.points[x];
var b = poly2.points[(x + 1) % poly2.points.length];
a.connectedTo.push(b);
b.connectedTo.push(a);
}
//Setup constrains
poly2.constrains.push({ a: poly2.points[0], b: poly2.points[1], key: 'x', offset: 50 }, { a: poly2.points[0], b: poly2.points[1], key: 'y', offset: 50 });
//Generate sketch
var s = new Sketch([poly1, poly2]);
<!-- TYPESCRIPT -->
<!--
class Point {
\t constructor(public x: number, public y: number, public connectedTo: Point[] = []) {
\t }
}
interface IConstrain {
\t a: Point,
\t b: Point,
\t key: string,
\t offset?: number
}
class Polygon {
\t constructor(public points: Point[], public constrains: IConstrain[] = []) {
\t }
}
class Sketch {
\t public ctx: CanvasRenderingContext2D;
\t constructor(public polygons: Polygon[] = [], public canvas = document.body.appendChild(document.createElement("canvas"))) {
\t \t this.canvas.width = 1000;
\t \t this.canvas.height = 1000;
\t \t this.ctx = this.canvas.getContext("2d");
\t \t this.ctx.fillStyle = "#0971CE";
\t \t this.ctx.strokeStyle = "white";
\t \t this.canvas.onmousedown = this.clickHandler.bind(this)
\t \t this.canvas.onmouseup = this.clickHandler.bind(this)
\t \t this.canvas.onmousemove = this.clickHandler.bind(this)
\t \t requestAnimationFrame(this.draw.bind(this))
\t }
\t public selectedPoint: Point
\t public clickHandler(evt: MouseEvent) {
\t \t if (evt.type == "mousedown") {
\t \t \t if (this.selectedPoint != void 0) {
\t \t \t \t this.selectedPoint = null;
\t \t \t } else {
\t \t \t \t let score = null;
\t \t \t \t let best = null;
\t \t \t \t for (let p = 0; p < this.polygons.length; p++) {
\t \t \t \t \t let polygon = this.polygons[p];
\t \t \t \t \t for (let pi = 0; pi < polygon.points.length; pi++) {
\t \t \t \t \t \t let point = polygon.points[pi];
\t \t \t \t \t \t let dist = Math.abs(point.x - evt.offsetX) + Math.abs(point.y - evt.offsetY)
\t \t \t \t \t \t if (score == null ? true : dist < score) {
\t \t \t \t \t \t \t score = dist;
\t \t \t \t \t \t \t best = point;
\t \t \t \t \t \t }
\t \t \t \t \t }
\t \t \t \t }
\t \t \t \t this.selectedPoint = best;
\t \t \t }
\t \t }
\t \t if (evt.type == "mousemove" && this.selectedPoint != void 0) {
\t \t \t this.selectedPoint.x = Math.round(evt.offsetX/5) * 5;
\t \t \t this.selectedPoint.y = Math.round(evt.offsetY/5) * 5;
\t \t \t for (let pi = 0; pi < this.polygons.length; pi++) {
\t \t \t \t let polygon = this.polygons[pi];
\t \t \t \t if (polygon.points.indexOf(this.selectedPoint) < 0) {
\t \t \t \t \t continue;
\t \t \t \t }
\t \t \t \t for (let pa = 0; pa < polygon.constrains.length; pa++) {
\t \t \t \t \t let constrain = polygon.constrains[pa];
\t \t \t \t \t if (constrain.a == this.selectedPoint || constrain.b == this.selectedPoint) {
\t \t \t \t \t \t constrain.a[constrain.key] = this.selectedPoint[constrain.key]
\t \t \t \t \t \t constrain.b[constrain.key] = this.selectedPoint[constrain.key]
\t \t \t \t \t \t if (constrain.offset != void 0) {
\t \t \t \t \t \t \t if (constrain.a == this.selectedPoint) {
\t \t \t \t \t \t \t \t constrain.b[constrain.key] += constrain.offset
\t \t \t \t \t \t \t } else {
\t \t \t \t \t \t \t \t constrain.a[constrain.key] -= constrain.offset
\t \t \t \t \t \t \t }
\t \t \t \t \t \t }
\t \t \t \t \t }
\t \t \t \t }
\t \t \t }
\t \t }
\t \t requestAnimationFrame(this.draw.bind(this))
\t }
\t public draw() {
\t \t var ctx = this.ctx;
\t \t //clear
\t \t ctx.fillStyle = "#0971CE";
\t \t ctx.fillRect(0, 0, 1000, 1000)
\t \t //grid
\t \t ctx.strokeStyle = "rgba(255,255,255,0.25)"
\t \t for (let x = 0; x <= this.canvas.width; x += 5) {
\t \t \t ctx.beginPath()
\t \t \t ctx.moveTo(x, -1)
\t \t \t ctx.lineTo(x, this.canvas.height)
\t \t \t ctx.stroke();
\t \t \t ctx.closePath()
\t \t }
\t \t for (let y = 0; y <= this.canvas.height; y += 5) {
\t \t \t ctx.beginPath()
\t \t \t ctx.moveTo(-1, y)
\t \t \t ctx.lineTo(this.canvas.width, y)
\t \t \t ctx.stroke();
\t \t \t ctx.closePath()
\t \t }
\t \t ctx.strokeStyle = "white"
\t \t ctx.fillStyle = "white";
\t \t //shapes
\t \t for (let i = 0; i < this.polygons.length; i++) {
\t \t \t let polygon = this.polygons[i];
\t \t \t for (let pa = 0; pa < polygon.points.length; pa++) {
\t \t \t \t let pointa = polygon.points[pa];
\t \t \t \t if (pointa == this.selectedPoint) {
\t \t \t \t \t ctx.beginPath();
\t \t \t \t \t ctx.fillRect(pointa.x - 2, pointa.y - 2, 4, 4)
\t \t \t \t \t ctx.closePath();
\t \t \t \t }
\t \t \t \t ctx.beginPath();
\t \t \t \t for (var pb = 0; pb < pointa.connectedTo.length; pb++) {
\t \t \t \t \t var pointb = pointa.connectedTo[pb];
\t \t \t \t \t if (polygon.points.indexOf(pointb) < pa) {
\t \t \t \t \t \t continue;
\t \t \t \t \t }
\t \t \t \t \t ctx.moveTo(pointa.x, pointa.y)
\t \t \t \t \t ctx.lineTo(pointb.x, pointb.y)
\t \t \t \t }
\t \t \t \t ctx.stroke();
\t \t \t \t ctx.closePath();
\t \t \t }
\t \t }
\t }
}
//==Test==
//Build polygon 1 (House)
var poly1 = new Polygon([
\t new Point(10, 10),
\t new Point(80, 10),
\t new Point(80, 45),
\t new Point(130, 45),
\t new Point(130, 95),
\t new Point(80, 95),
\t new Point(80, 135),
\t new Point(10, 135),
])
//Connect dots
for (let x = 0; x < poly1.points.length; x++) {
\t let a = poly1.points[x];
\t let b = poly1.points[(x + 1) % poly1.points.length]
\t a.connectedTo.push(b)
\t b.connectedTo.push(a)
}
//Setup constrains
for (let x = 0; x < poly1.points.length; x++) {
\t let a = poly1.points[x];
\t let b = poly1.points[(x + 1) % poly1.points.length]
\t poly1.constrains.push({ a: a, b: b, key: x % 2 == 1 ? 'x' : 'y' })
}
poly1.constrains.push(
\t { a: poly1.points[1], b: poly1.points[5], key: 'x' },
\t { a: poly1.points[2], b: poly1.points[5], key: 'x' },
\t { a: poly1.points[1], b: poly1.points[6], key: 'x' },
\t { a: poly1.points[2], b: poly1.points[6], key: 'x' }
)
//Build polygon 2 (Triangle)
var poly2 = new Polygon([
\t new Point(250, 250),
\t new Point(300, 300),
\t new Point(200, 300),
])
//Connect dots
for (let x = 0; x < poly2.points.length; x++) {
\t let a = poly2.points[x];
\t let b = poly2.points[(x + 1) % poly2.points.length]
\t a.connectedTo.push(b)
\t b.connectedTo.push(a)
}
//Setup constrains
poly2.constrains.push(
\t { a: poly2.points[0], b: poly2.points[1], key: 'x', offset: 50 },
\t { a: poly2.points[0], b: poly2.points[1], key: 'y', offset: 50 },
)
//Generate sketch
var s = new Sketch([poly1, poly2])
-->
*任何*幾何形狀?我很肯定,如果你有一個廣義的形狀,定義這種形狀約束將非常困難 – meowgoesthedog
是的,我現在正在修改這個問題,給出更多的例子。 你是對的@meowgoesthedog,我會嘗試更具體的形狀。 –
我刪除了我的評論,+1改善問題,這就是它應該是這樣:) – slhck