294 lines
12 KiB
JavaScript
294 lines
12 KiB
JavaScript
////////////////////////////////////////////////////////////
|
|
//// © Microsoft. All rights reserved. ////
|
|
////////////////////////////////////////////////////////////
|
|
|
|
(function (AppNS) {
|
|
'use strict';
|
|
|
|
var Path = WinJS.Class.define(
|
|
|
|
// Constructor
|
|
function (data) {
|
|
|
|
// Params
|
|
this.minDist = 3; // Minumum distance before a point is added to the path
|
|
this.weight = 0.3; // Bezier weight of control points
|
|
|
|
this.p1 = null; // The first point
|
|
this.p2 = null; // The second point
|
|
this.p3 = null; // The third point (most recent)
|
|
this.box1 = null; // Touch bounding box data for the first point
|
|
this.box2 = null; // Touch bounding box data for the second point
|
|
this.box3 = null; // Touch bounding box data for the third point
|
|
this.dist = 0; // Current distance between the start and end points of the bezier curve
|
|
|
|
this.wStart = 0; // The width of the line at the beginning of the curve
|
|
this.wEnd = 0; // The width of the line at the end of the curve
|
|
|
|
this.dirStart = new AppNS.Painter.Math.Vector(0, 0); // Direction at beginning of curve
|
|
this.dirEnd = new AppNS.Painter.Math.Vector(0, 0); // Direction at the end of curve
|
|
this.perpStart = new AppNS.Painter.Math.Vector(0, 0); // Perpendicular at beginning of curve
|
|
this.perpEnd = new AppNS.Painter.Math.Vector(0, 0); // Perpendicular at end of curve
|
|
|
|
this.pStart = new AppNS.Painter.Math.Point(0, 0); // Point at beginning of curve
|
|
this.cpStart = new AppNS.Painter.Math.Point(0, 0); // Bezier control point at beginning of curve
|
|
this.cpEnd = new AppNS.Painter.Math.Point(0, 0); // Bezier control point at end of curve
|
|
this.pEnd = new AppNS.Painter.Math.Point(0, 0); // Point at end of curve
|
|
|
|
this.newPoint = false; // True if the there is a new point added to the path
|
|
|
|
if (data.x || data.y) {
|
|
this.p3 = new AppNS.Painter.Math.Point(data.x, data.y); // The third point (most recent)
|
|
} else {
|
|
throw new Error("PaintPlay - Error: Path object requires x and y data info.");
|
|
}
|
|
if (data.w && data.h) {
|
|
this.box3 = new AppNS.Painter.Math.Vector(data.w, data.h);
|
|
}
|
|
},
|
|
|
|
// Variables and Methods
|
|
{
|
|
|
|
// True if there is information necessary to draw the start of a curve (2 points)
|
|
starting: {
|
|
get: function () {
|
|
return (this.newPoint && this.numPoints() === 2);
|
|
}
|
|
},
|
|
|
|
// True if this path is new (1 point)
|
|
created: {
|
|
get: function () {
|
|
return (this.numPoints() === 1);
|
|
}
|
|
},
|
|
|
|
// True if this path is drawable (3 points)
|
|
drawable: {
|
|
get: function () {
|
|
return (this.newPoint && this.numPoints() === 3);
|
|
}
|
|
},
|
|
|
|
numPoints: function () {
|
|
if (this.p1) {
|
|
return 3;
|
|
} else if (this.p2) {
|
|
return 2;
|
|
} else if (this.p3) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
},
|
|
|
|
// Adds the given point to the path
|
|
addPoint: function (data) {
|
|
// Add the new point if mouse moved far enough
|
|
if (data.x || data.y) {
|
|
var p = new AppNS.Painter.Math.Point(data.x, data.y);
|
|
} else {
|
|
throw new Error("PaintPlay - Error: Path object requires x and y data info.");
|
|
}
|
|
if (data.w && data.h) {
|
|
var box = new AppNS.Painter.Math.Vector(data.w, data.h);
|
|
}
|
|
|
|
if (this.p3.distanceTo(p) > this.minDist) {
|
|
this.newPoint = true;
|
|
|
|
// Reset the points of the curve
|
|
this.p1 = this.p2;
|
|
this.p2 = this.p3;
|
|
this.p3 = p;
|
|
this.box1 = this.box2;
|
|
this.box2 = this.box3;
|
|
this.box3 = box;
|
|
|
|
// If only have two points, initialize first direction vector
|
|
if (!this.p1) {
|
|
|
|
// Find the current distance
|
|
this.dist = this.p2.distanceTo(this.p3);
|
|
|
|
// Initialize tangent info
|
|
this.dirEnd.fromPoints(this.p2, this.p3);
|
|
this.dirEnd.normalize();
|
|
this.perpEnd.fromVector(this.dirEnd);
|
|
this.perpEnd.toPerp();
|
|
this.perpEnd.normalize();
|
|
|
|
} else {
|
|
// otherwise, we have all three points
|
|
|
|
// Find the current distance
|
|
this.dist = this.p1.distanceTo(this.p2);
|
|
|
|
// Set start and end tangent info
|
|
this.dirStart.fromVector(this.dirEnd);
|
|
this.dirEnd.fromPoints(this.p1, this.p3);
|
|
this.dirEnd.normalize();
|
|
|
|
// Set perpendicular vectors from start and end tangents
|
|
this.perpStart.fromVector(this.perpEnd);
|
|
this.perpEnd.fromVector(this.dirEnd);
|
|
this.perpEnd.toPerp();
|
|
this.perpEnd.normalize();
|
|
}
|
|
} else {
|
|
this.newPoint = false;
|
|
}
|
|
},
|
|
|
|
// Calculates the end Bezier curve info
|
|
calculateEndBezier: function (offsetStart, offsetEnd, inertia) {
|
|
if (this.p2 && this.p3) {
|
|
// If offset given, use it
|
|
var c2 = offsetStart || 0;
|
|
var c3 = offsetEnd || 0;
|
|
inertia = inertia || 0;
|
|
|
|
var dir3 = new AppNS.Painter.Math.Vector();
|
|
dir3.fromPoints(this.p2, this.p3);
|
|
dir3.normalize();
|
|
|
|
var perp3 = new AppNS.Painter.Math.Vector();
|
|
perp3.fromVector(dir3);
|
|
perp3.toPerp();
|
|
perp3.normalize();
|
|
|
|
// First bezier point
|
|
this.pStart.fromPoint(this.p2);
|
|
this.pStart.scaleAdd(this.perpEnd, c2);
|
|
|
|
// Last bezier point
|
|
this.pEnd.fromPoint(this.p3);
|
|
this.pEnd.scaleAdd(perp3, c3);
|
|
this.pEnd.scaleAdd(dir3, inertia);
|
|
|
|
var dist = this.pStart.distanceTo(this.pEnd);
|
|
|
|
// First control point
|
|
this.cpStart.fromPoint(this.pStart);
|
|
this.cpStart.scaleAdd(this.dirEnd, dist * this.weight);
|
|
|
|
// Second control point
|
|
this.cpEnd.fromPoint(this.pEnd);
|
|
this.cpEnd.scaleAdd(dir3, -1 * dist * this.weight);
|
|
}
|
|
},
|
|
|
|
calculateInertia: function (inertia, dist, min, max) {
|
|
var cInertia = dist * inertia;
|
|
if (cInertia < min) {
|
|
cInertia = min;
|
|
} else if (cInertia > max) {
|
|
cInertia = max;
|
|
}
|
|
return cInertia;
|
|
},
|
|
|
|
calculateStartCurve: function (offsetTop, offsetBottom, inertia, minInertia, overlap) {
|
|
if (this.p2 && this.p3) {
|
|
// If offset given, use it
|
|
var cTop = offsetTop || 0;
|
|
var cBottom = offsetBottom || 0;
|
|
var cOverlap = overlap || 0;
|
|
var cInertia = -this.calculateInertia(inertia, this.dist, minInertia, 4 * minInertia);
|
|
|
|
// First bezier point
|
|
this.pStart.fromPoint(this.p2);
|
|
this.pStart.scaleAdd(this.dirEnd, cOverlap);
|
|
this.pStart.scaleAdd(this.perpEnd, -1 * cBottom);
|
|
|
|
// Last bezier point
|
|
this.pEnd.fromPoint(this.p2);
|
|
this.pEnd.scaleAdd(this.dirEnd, cOverlap);
|
|
this.pEnd.scaleAdd(this.perpEnd, cTop);
|
|
|
|
// First control point
|
|
this.cpStart.fromPoint(this.pStart);
|
|
this.cpStart.scaleAdd(this.dirEnd, cInertia);
|
|
|
|
// Second control point
|
|
this.cpEnd.fromPoint(this.pEnd);
|
|
this.cpEnd.scaleAdd(this.dirEnd, cInertia);
|
|
}
|
|
},
|
|
|
|
calculateStopCurve: function (offsetTop, offsetBottom, inertia, minInertia, overlap) {
|
|
if (this.p2 && this.p3) {
|
|
// If offset given, use it
|
|
var cTop = offsetTop || 0;
|
|
var cBottom = offsetBottom || 0;
|
|
var cOverlap = overlap || 0;
|
|
var cInertia = this.calculateInertia(inertia, this.dist, minInertia, 4 * minInertia);
|
|
|
|
// First bezier point
|
|
this.pStart.fromPoint(this.p2);
|
|
this.pStart.scaleAdd(this.dirEnd, -cOverlap);
|
|
this.pStart.scaleAdd(this.perpEnd, -1 * cBottom);
|
|
|
|
// Last bezier point
|
|
this.pEnd.fromPoint(this.p2);
|
|
this.pEnd.scaleAdd(this.dirEnd, -cOverlap);
|
|
this.pEnd.scaleAdd(this.perpEnd, cTop);
|
|
|
|
// First control point
|
|
this.cpStart.fromPoint(this.pStart);
|
|
this.cpStart.scaleAdd(this.dirEnd, cInertia);
|
|
|
|
// Second control point
|
|
this.cpEnd.fromPoint(this.pEnd);
|
|
this.cpEnd.scaleAdd(this.dirEnd, cInertia);
|
|
}
|
|
},
|
|
|
|
// Calculates the Bezier curve info.
|
|
// Offsets are the number of pixels perpendicular to main points (shifts curve up or down).
|
|
calculateBezier: function (offsetStart, offsetEnd, overlap) {
|
|
|
|
// If offset given, use it
|
|
var c1 = offsetStart || 0;
|
|
var c2 = offsetEnd || 0;
|
|
var c3 = overlap || 0;
|
|
|
|
// First bezier point
|
|
this.pStart.fromPoint(this.p1);
|
|
this.pStart.scaleAdd(this.dirStart, -c3);
|
|
this.pStart.scaleAdd(this.perpStart, c1);
|
|
|
|
// Last bezier point
|
|
this.pEnd.fromPoint(this.p2);
|
|
this.pEnd.scaleAdd(this.dirEnd, c3);
|
|
this.pEnd.scaleAdd(this.perpEnd, c2);
|
|
|
|
var dist = this.pStart.distanceTo(this.pEnd);
|
|
|
|
// First control point
|
|
this.cpStart.fromPoint(this.pStart);
|
|
this.cpStart.scaleAdd(this.dirStart, dist * this.weight);
|
|
|
|
// Second control point
|
|
this.cpEnd.fromPoint(this.pEnd);
|
|
this.cpEnd.scaleAdd(this.dirEnd, -1 * dist * this.weight);
|
|
},
|
|
|
|
// Calculates the line width based on touch-box data
|
|
calculateWidth: function () {
|
|
if (this.box1 && this.box2) {
|
|
this.wStart = this.box1.componentIn(this.perpStart);
|
|
this.wEnd = this.box2.componentIn(this.perpEnd);
|
|
} else {
|
|
this.wStart = 10;
|
|
this.wEnd = 30;
|
|
}
|
|
}
|
|
});
|
|
|
|
WinJS.Namespace.defineWithParent(AppNS, "Painter.Graphics", {
|
|
Path: Path
|
|
});
|
|
|
|
})(Microsoft.Paint);
|