221 lines
No EOL
10 KiB
JavaScript
221 lines
No EOL
10 KiB
JavaScript
////////////////////////////////////////////////////////////
|
|
//// © Microsoft. All rights reserved. ////
|
|
////////////////////////////////////////////////////////////
|
|
|
|
(function (AppNS) {
|
|
'use strict';
|
|
|
|
// The Pipe tool has a 3D look to it
|
|
var Pipe = WinJS.Class.define(
|
|
|
|
// Constructor
|
|
function () {
|
|
this.autoWidth = false; // Whether or not width is based on path touch-box data or manual width value
|
|
this.width = 20; // The default line manual width
|
|
this.height = 6; // The 'height' of the 3D pipe look, in pixels
|
|
this.maxHeight = 6;
|
|
this.numBristles = 0; // Number of bristles on each side of the pipe
|
|
this.bristles = []; // All of the pipe bristles
|
|
this.pxPerBristle = 1; // The width of each bristle in pixels
|
|
this.middleBristle = new AppNS.Painter.Tools.Bristle();
|
|
},
|
|
|
|
// Variables and Methods
|
|
{
|
|
|
|
// Begins rendering the beginning of the path
|
|
renderStart: function (path, painter) {
|
|
var color = new AppNS.Painter.Graphics.Color();
|
|
color.fromColor(painter.color);
|
|
|
|
// If the color is dark, we lighten it
|
|
if (color.red + color.green + color.blue < 255 * 3 / 2) {
|
|
color.lighten(0.2);
|
|
}
|
|
|
|
// Inner Bristles
|
|
this.numBristles = Math.floor(0.25 * this.width / this.pxPerBristle);
|
|
if (this.numBristles <= 0) {
|
|
this.numBristles = 1;
|
|
}
|
|
|
|
for (var i = 0; i < this.numBristles; i++) {
|
|
this.bristles[i] = new AppNS.Painter.Tools.Bristle();
|
|
this.bristles[i].color.fromColor(color);
|
|
this.bristles[i].color.scale(1 - ((i + 1) / this.numBristles) * (this.height / this.maxHeight));
|
|
this.bristles[i].width = this.pxPerBristle;
|
|
}
|
|
|
|
// Large inner bristle
|
|
this.middleBristle.width = this.width - (this.numBristles * this.pxPerBristle * 2);
|
|
this.middleBristle.color.fromColor(color);
|
|
|
|
var ctx = painter.canvas.context;
|
|
ctx.shadowOffsetX = 0;
|
|
ctx.shadowOffsetY = 0;
|
|
ctx.shadowBlur = 0;
|
|
ctx.globalCompositeOperation = "source-over";
|
|
ctx.globalAlpha = 1.0;
|
|
},
|
|
|
|
// Renders the given path using the current style
|
|
render: function (path, painter) {
|
|
var ctx = painter.canvas.context;
|
|
|
|
// Get start and end widths for the stroke part
|
|
var wStart = this.width;
|
|
var wEnd = this.width;
|
|
if (this.autoWidth) {
|
|
path.calculateWidth();
|
|
wStart = path.wStart;
|
|
wEnd = path.wEnd;
|
|
}
|
|
|
|
var outerStart = this.middleBristle.width / 2;
|
|
var outerEnd = this.middleBristle.width / 2;
|
|
|
|
if (path.starting) {
|
|
|
|
// Draw each simulated bristle as a bezier curve
|
|
for (var i = this.numBristles - 1; i >= 0; i--) {
|
|
var offsetStart = (i + 0.5) * this.pxPerBristle + this.middleBristle.width / 2;
|
|
var offsetEnd = (i + 0.5) * this.pxPerBristle + this.middleBristle.width / 2;
|
|
|
|
ctx.strokeStyle = this.bristles[i].color.toString();
|
|
ctx.fillStyle = this.bristles[i].color.toString();
|
|
ctx.lineWidth = this.bristles[i].width;
|
|
|
|
// Draw the Bristle
|
|
path.calculateStartCurve(offsetStart, offsetEnd, 3, wEnd);
|
|
ctx.beginPath();
|
|
ctx.moveTo(path.pStart.x, path.pStart.y);
|
|
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
}
|
|
|
|
// Draw middle
|
|
path.calculateStartCurve(this.middleBristle.width / 2, this.middleBristle.width / 2, 3, wEnd);
|
|
ctx.beginPath();
|
|
ctx.moveTo(path.pStart.x, path.pStart.y);
|
|
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
|
|
ctx.closePath();
|
|
ctx.fillStyle = this.middleBristle.color.toString();
|
|
ctx.fill();
|
|
}
|
|
|
|
if (path.drawable) {
|
|
ctx.lineWidth = this.pxPerBristle + 0.5;
|
|
|
|
// Draw each simulated bristle as a bezier curve
|
|
for (var i = this.numBristles - 1; i >= 0; i--) {
|
|
var offsetStart = (i + 0.5) * this.pxPerBristle + outerStart;
|
|
var offsetEnd = (i + 0.5) * this.pxPerBristle + outerEnd;
|
|
var overlap = 1.5 * (1 - i / this.numBristles);
|
|
|
|
// Draw the middle bristle.
|
|
// Start at first point of shape, then bezier to second.
|
|
ctx.beginPath();
|
|
path.calculateBezier(offsetStart, offsetEnd, overlap);
|
|
ctx.moveTo(path.pStart.x, path.pStart.y);
|
|
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
|
|
|
|
// Line to third point of shape, then bezier to fourth, then close the path
|
|
path.calculateBezier(-offsetStart, -offsetEnd, overlap);
|
|
ctx.lineTo(path.pEnd.x, path.pEnd.y);
|
|
ctx.bezierCurveTo(path.cpEnd.x, path.cpEnd.y, path.cpStart.x, path.cpStart.y, path.pStart.x, path.pStart.y);
|
|
ctx.closePath();
|
|
|
|
// Set fill Style and fill shape
|
|
ctx.fillStyle = this.bristles[i].color.toString();
|
|
ctx.fill();
|
|
}
|
|
|
|
// Draw the middle bristle.
|
|
// Start at first point of shape, then bezier to second.
|
|
ctx.beginPath();
|
|
path.calculateBezier(outerStart, outerEnd, 2);
|
|
ctx.moveTo(path.pStart.x, path.pStart.y);
|
|
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
|
|
|
|
// Line to third point of shape, then bezier to fourth, then close the path
|
|
path.calculateBezier(-outerStart, -outerEnd, 2);
|
|
ctx.lineTo(path.pEnd.x, path.pEnd.y);
|
|
ctx.bezierCurveTo(path.cpEnd.x, path.cpEnd.y, path.cpStart.x, path.cpStart.y, path.pStart.x, path.pStart.y);
|
|
ctx.closePath();
|
|
|
|
// Set fill Style and fill shape
|
|
ctx.fillStyle = this.middleBristle.color.toString();
|
|
ctx.fill();
|
|
}
|
|
},
|
|
|
|
// Renders the end of the path with the current style
|
|
renderStop: function (path, painter) {
|
|
var ctx = painter.canvas.context;
|
|
|
|
// Get start and end widths for the stroke part
|
|
var wStart = this.width;
|
|
var wEnd = this.width;
|
|
if (this.autoWidth){
|
|
path.calculateWidth();
|
|
wStart = path.wStart;
|
|
wEnd = path.wEnd;
|
|
}
|
|
|
|
// If haven't drawn starting effect yet
|
|
if (path.created || path.starting) {
|
|
var x = path.p3.x;
|
|
var y = path.p3.y;
|
|
|
|
// Draw bristles
|
|
for (var i = this.numBristles - 1; i >= 0; i--) {
|
|
var radius = (i + 0.5) * this.pxPerBristle + this.middleBristle.width / 2;
|
|
|
|
// Draw the Bristle
|
|
ctx.fillStyle = this.bristles[i].color.toString();
|
|
painter.canvas.drawCircle(x, y, radius);
|
|
}
|
|
|
|
// Draw middle
|
|
ctx.fillStyle = this.middleBristle.color.toString();
|
|
painter.canvas.drawCircle(x, y, this.middleBristle.width / 2);
|
|
|
|
} else { // Otherwise, draw a curve to end the path
|
|
|
|
// Draw each simulated bristle as a bezier curve
|
|
for (var i = this.numBristles - 1; i >= 0; i--) {
|
|
var offsetStart = (i + 0.5) * this.pxPerBristle + this.middleBristle.width / 2;
|
|
var offsetEnd = (i + 0.5) * this.pxPerBristle + this.middleBristle.width / 2;
|
|
var overlap = 1.5 * (1 - i / this.numBristles);
|
|
|
|
ctx.fillStyle = this.bristles[i].color.toString();
|
|
ctx.lineWidth = this.bristles[i].width;
|
|
|
|
// Draw the Bristle
|
|
path.calculateStopCurve(offsetStart, offsetEnd, 3, wEnd, overlap);
|
|
ctx.beginPath();
|
|
ctx.moveTo(path.pStart.x, path.pStart.y);
|
|
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
}
|
|
|
|
// Draw middle
|
|
path.calculateStopCurve(this.middleBristle.width / 2, this.middleBristle.width / 2, 3, wEnd, 2);
|
|
ctx.beginPath();
|
|
ctx.moveTo(path.pStart.x, path.pStart.y);
|
|
ctx.bezierCurveTo(path.cpStart.x, path.cpStart.y, path.cpEnd.x, path.cpEnd.y, path.pEnd.x, path.pEnd.y);
|
|
ctx.closePath();
|
|
ctx.fillStyle = this.middleBristle.color.toString();
|
|
ctx.fill();
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
WinJS.Namespace.defineWithParent(AppNS, "Painter.Tools", {
|
|
Pipe: Pipe
|
|
});
|
|
|
|
})(Microsoft.Paint); |