1*c8dee2aaSAndroid Build Coastguard Worker 2*c8dee2aaSAndroid Build Coastguard Workerdescribe('PathKit\'s Path Behavior', function() { 3*c8dee2aaSAndroid Build Coastguard Worker // see https://fiddle.skia.org/c/@discrete_path 4*c8dee2aaSAndroid Build Coastguard Worker function drawStar() { 5*c8dee2aaSAndroid Build Coastguard Worker let path = PathKit.NewPath(); 6*c8dee2aaSAndroid Build Coastguard Worker let R = 115.2, C = 128.0; 7*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(C + R + 22, C); 8*c8dee2aaSAndroid Build Coastguard Worker for (let i = 1; i < 8; i++) { 9*c8dee2aaSAndroid Build Coastguard Worker let a = 2.6927937 * i; 10*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(C + R * Math.cos(a) + 22, C + R * Math.sin(a)); 11*c8dee2aaSAndroid Build Coastguard Worker } 12*c8dee2aaSAndroid Build Coastguard Worker path.closePath(); 13*c8dee2aaSAndroid Build Coastguard Worker return path; 14*c8dee2aaSAndroid Build Coastguard Worker } 15*c8dee2aaSAndroid Build Coastguard Worker 16*c8dee2aaSAndroid Build Coastguard Worker describe('Dash Path Effect', function() { 17*c8dee2aaSAndroid Build Coastguard Worker it('performs dash in-place with start, stop, phase', function(done) { 18*c8dee2aaSAndroid Build Coastguard Worker LoadPathKit.then(catchException(done, () => { 19*c8dee2aaSAndroid Build Coastguard Worker let orig = drawStar(); 20*c8dee2aaSAndroid Build Coastguard Worker let dashed = drawStar(); 21*c8dee2aaSAndroid Build Coastguard Worker let notACopy = dashed.dash(10, 3, 0); 22*c8dee2aaSAndroid Build Coastguard Worker let phased = drawStar().dash(10, 3, 2); 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker expect(dashed === notACopy).toBe(true); 25*c8dee2aaSAndroid Build Coastguard Worker expect(dashed.equals(phased)).toBe(false); 26*c8dee2aaSAndroid Build Coastguard Worker expect(dashed.equals(orig)).toBe(false); 27*c8dee2aaSAndroid Build Coastguard Worker 28*c8dee2aaSAndroid Build Coastguard Worker reportPath(dashed, 'dashed_no_phase', () => { 29*c8dee2aaSAndroid Build Coastguard Worker reportPath(phased, 'dashed_with_phase', done); 30*c8dee2aaSAndroid Build Coastguard Worker orig.delete(); 31*c8dee2aaSAndroid Build Coastguard Worker dashed.delete(); 32*c8dee2aaSAndroid Build Coastguard Worker phased.delete(); 33*c8dee2aaSAndroid Build Coastguard Worker }); 34*c8dee2aaSAndroid Build Coastguard Worker })); 35*c8dee2aaSAndroid Build Coastguard Worker }); 36*c8dee2aaSAndroid Build Coastguard Worker }); 37*c8dee2aaSAndroid Build Coastguard Worker 38*c8dee2aaSAndroid Build Coastguard Worker describe('Trim Path Effect', function() { 39*c8dee2aaSAndroid Build Coastguard Worker it('performs trim in-place with start, stop, phase', function(done) { 40*c8dee2aaSAndroid Build Coastguard Worker LoadPathKit.then(catchException(done, () => { 41*c8dee2aaSAndroid Build Coastguard Worker let orig = drawStar(); 42*c8dee2aaSAndroid Build Coastguard Worker let trimmed = drawStar(); 43*c8dee2aaSAndroid Build Coastguard Worker let notACopy = trimmed.trim(0.25, .8); 44*c8dee2aaSAndroid Build Coastguard Worker let complement = drawStar().trim(.1, .9, true); 45*c8dee2aaSAndroid Build Coastguard Worker 46*c8dee2aaSAndroid Build Coastguard Worker expect(trimmed === notACopy).toBe(true); 47*c8dee2aaSAndroid Build Coastguard Worker expect(trimmed.equals(complement)).toBe(false); 48*c8dee2aaSAndroid Build Coastguard Worker expect(trimmed.equals(orig)).toBe(false); 49*c8dee2aaSAndroid Build Coastguard Worker expect(complement.equals(orig)).toBe(false); 50*c8dee2aaSAndroid Build Coastguard Worker 51*c8dee2aaSAndroid Build Coastguard Worker reportPath(trimmed, 'trimmed_non_complement', () => { 52*c8dee2aaSAndroid Build Coastguard Worker reportPath(complement, 'trimmed_complement', done); 53*c8dee2aaSAndroid Build Coastguard Worker orig.delete(); 54*c8dee2aaSAndroid Build Coastguard Worker trimmed.delete(); 55*c8dee2aaSAndroid Build Coastguard Worker complement.delete(); 56*c8dee2aaSAndroid Build Coastguard Worker }); 57*c8dee2aaSAndroid Build Coastguard Worker })); 58*c8dee2aaSAndroid Build Coastguard Worker }); 59*c8dee2aaSAndroid Build Coastguard Worker }); 60*c8dee2aaSAndroid Build Coastguard Worker 61*c8dee2aaSAndroid Build Coastguard Worker describe('Transform Path Effect', function() { 62*c8dee2aaSAndroid Build Coastguard Worker it('performs matrix transform in-place', function(done) { 63*c8dee2aaSAndroid Build Coastguard Worker LoadPathKit.then(catchException(done, () => { 64*c8dee2aaSAndroid Build Coastguard Worker let orig = drawStar(); 65*c8dee2aaSAndroid Build Coastguard Worker let scaled = drawStar(); 66*c8dee2aaSAndroid Build Coastguard Worker let notACopy = scaled.transform(3, 0, 0, 67*c8dee2aaSAndroid Build Coastguard Worker 0, 3, 0, 68*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 1); 69*c8dee2aaSAndroid Build Coastguard Worker 70*c8dee2aaSAndroid Build Coastguard Worker let scaled2 = drawStar().transform([3, 0, 0, 71*c8dee2aaSAndroid Build Coastguard Worker 0, 3, 0, 72*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 1]); 73*c8dee2aaSAndroid Build Coastguard Worker 74*c8dee2aaSAndroid Build Coastguard Worker expect(scaled === notACopy).toBe(true); 75*c8dee2aaSAndroid Build Coastguard Worker expect(scaled.equals(scaled2)).toBe(true); 76*c8dee2aaSAndroid Build Coastguard Worker expect(scaled.equals(orig)).toBe(false); 77*c8dee2aaSAndroid Build Coastguard Worker 78*c8dee2aaSAndroid Build Coastguard Worker reportPath(scaled, 'transformed_scale', () => { 79*c8dee2aaSAndroid Build Coastguard Worker reportPath(scaled2, 'transformed_scale2', done); 80*c8dee2aaSAndroid Build Coastguard Worker orig.delete(); 81*c8dee2aaSAndroid Build Coastguard Worker scaled.delete(); 82*c8dee2aaSAndroid Build Coastguard Worker scaled2.delete(); 83*c8dee2aaSAndroid Build Coastguard Worker }); 84*c8dee2aaSAndroid Build Coastguard Worker })); 85*c8dee2aaSAndroid Build Coastguard Worker }); 86*c8dee2aaSAndroid Build Coastguard Worker }); 87*c8dee2aaSAndroid Build Coastguard Worker 88*c8dee2aaSAndroid Build Coastguard Worker describe('Stroke Path Effect', function() { 89*c8dee2aaSAndroid Build Coastguard Worker it('creates a stroked path in-place', function(done) { 90*c8dee2aaSAndroid Build Coastguard Worker LoadPathKit.then(catchException(done, () => { 91*c8dee2aaSAndroid Build Coastguard Worker let orig = drawStar(); 92*c8dee2aaSAndroid Build Coastguard Worker let stroked = drawStar(); 93*c8dee2aaSAndroid Build Coastguard Worker let notACopy = stroked.stroke({ 94*c8dee2aaSAndroid Build Coastguard Worker width: 15, 95*c8dee2aaSAndroid Build Coastguard Worker join: PathKit.StrokeJoin.BEVEL, 96*c8dee2aaSAndroid Build Coastguard Worker cap: PathKit.StrokeCap.BUTT, 97*c8dee2aaSAndroid Build Coastguard Worker miter_limit: 2, 98*c8dee2aaSAndroid Build Coastguard Worker }); 99*c8dee2aaSAndroid Build Coastguard Worker 100*c8dee2aaSAndroid Build Coastguard Worker // Don't have to specify all of the fields, defaults will 101*c8dee2aaSAndroid Build Coastguard Worker // be used instead. 102*c8dee2aaSAndroid Build Coastguard Worker let rounded = drawStar().stroke({ 103*c8dee2aaSAndroid Build Coastguard Worker width: 10, 104*c8dee2aaSAndroid Build Coastguard Worker join: PathKit.StrokeJoin.ROUND, 105*c8dee2aaSAndroid Build Coastguard Worker cap:PathKit.StrokeCap.SQUARE, 106*c8dee2aaSAndroid Build Coastguard Worker }); 107*c8dee2aaSAndroid Build Coastguard Worker 108*c8dee2aaSAndroid Build Coastguard Worker expect(stroked === notACopy).toBe(true); 109*c8dee2aaSAndroid Build Coastguard Worker expect(stroked.equals(rounded)).toBe(false); 110*c8dee2aaSAndroid Build Coastguard Worker expect(stroked.equals(orig)).toBe(false); 111*c8dee2aaSAndroid Build Coastguard Worker 112*c8dee2aaSAndroid Build Coastguard Worker reportPath(stroked, 'stroke_bevel_butt', () => { 113*c8dee2aaSAndroid Build Coastguard Worker reportPath(rounded, 'stroke_round_square', done); 114*c8dee2aaSAndroid Build Coastguard Worker orig.delete(); 115*c8dee2aaSAndroid Build Coastguard Worker stroked.delete(); 116*c8dee2aaSAndroid Build Coastguard Worker rounded.delete(); 117*c8dee2aaSAndroid Build Coastguard Worker }); 118*c8dee2aaSAndroid Build Coastguard Worker })); 119*c8dee2aaSAndroid Build Coastguard Worker }); 120*c8dee2aaSAndroid Build Coastguard Worker 121*c8dee2aaSAndroid Build Coastguard Worker it('can use res_scale for more precision', function(done) { 122*c8dee2aaSAndroid Build Coastguard Worker LoadPathKit.then(catchException(done, () => { 123*c8dee2aaSAndroid Build Coastguard Worker let canvas = document.createElement('canvas'); 124*c8dee2aaSAndroid Build Coastguard Worker let ctx = canvas.getContext('2d'); 125*c8dee2aaSAndroid Build Coastguard Worker // Set canvas size and make it a bit bigger to zoom in on the lines 126*c8dee2aaSAndroid Build Coastguard Worker standardizedCanvasSize(ctx); 127*c8dee2aaSAndroid Build Coastguard Worker 128*c8dee2aaSAndroid Build Coastguard Worker const circle = PathKit.NewPath(); 129*c8dee2aaSAndroid Build Coastguard Worker circle.ellipse(0, 0, 1, 1, 0, 0, Math.PI * 2); 130*c8dee2aaSAndroid Build Coastguard Worker 131*c8dee2aaSAndroid Build Coastguard Worker let scales = [1, 3, 5, 132*c8dee2aaSAndroid Build Coastguard Worker 10, 30, 100]; 133*c8dee2aaSAndroid Build Coastguard Worker 134*c8dee2aaSAndroid Build Coastguard Worker // White background 135*c8dee2aaSAndroid Build Coastguard Worker ctx.fillStyle = 'white'; 136*c8dee2aaSAndroid Build Coastguard Worker ctx.fillRect(0, 0, canvas.width, canvas.height); 137*c8dee2aaSAndroid Build Coastguard Worker 138*c8dee2aaSAndroid Build Coastguard Worker for (let i = 0; i < scales.length; i++) { 139*c8dee2aaSAndroid Build Coastguard Worker ctx.save(); 140*c8dee2aaSAndroid Build Coastguard Worker const row = Math.floor(i / 3); 141*c8dee2aaSAndroid Build Coastguard Worker const col = i % 3; 142*c8dee2aaSAndroid Build Coastguard Worker ctx.translate(100 * col + 50, 100 * row + 50); 143*c8dee2aaSAndroid Build Coastguard Worker ctx.scale(30, 30); 144*c8dee2aaSAndroid Build Coastguard Worker 145*c8dee2aaSAndroid Build Coastguard Worker // Grey circle 146*c8dee2aaSAndroid Build Coastguard Worker ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; 147*c8dee2aaSAndroid Build Coastguard Worker ctx.beginPath(); 148*c8dee2aaSAndroid Build Coastguard Worker circle.toCanvas(ctx); 149*c8dee2aaSAndroid Build Coastguard Worker ctx.fill(); 150*c8dee2aaSAndroid Build Coastguard Worker 151*c8dee2aaSAndroid Build Coastguard Worker // Pink stroke, with given res_scale option 152*c8dee2aaSAndroid Build Coastguard Worker const line = circle.copy().stroke({ 153*c8dee2aaSAndroid Build Coastguard Worker width: 0.5, 154*c8dee2aaSAndroid Build Coastguard Worker res_scale: scales[i], 155*c8dee2aaSAndroid Build Coastguard Worker }); 156*c8dee2aaSAndroid Build Coastguard Worker ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; 157*c8dee2aaSAndroid Build Coastguard Worker ctx.beginPath(); 158*c8dee2aaSAndroid Build Coastguard Worker line.toCanvas(ctx); 159*c8dee2aaSAndroid Build Coastguard Worker ctx.fill(); 160*c8dee2aaSAndroid Build Coastguard Worker 161*c8dee2aaSAndroid Build Coastguard Worker line.delete(); 162*c8dee2aaSAndroid Build Coastguard Worker ctx.restore(); 163*c8dee2aaSAndroid Build Coastguard Worker } 164*c8dee2aaSAndroid Build Coastguard Worker ctx.fillStyle = 'black'; 165*c8dee2aaSAndroid Build Coastguard Worker ctx.font = '14px serif'; 166*c8dee2aaSAndroid Build Coastguard Worker ctx.fillText('notice for lower res_scale values, the stroked circles ' + 167*c8dee2aaSAndroid Build Coastguard Worker '(pink) are not round', 168*c8dee2aaSAndroid Build Coastguard Worker 10, 200); 169*c8dee2aaSAndroid Build Coastguard Worker 170*c8dee2aaSAndroid Build Coastguard Worker circle.delete(); 171*c8dee2aaSAndroid Build Coastguard Worker reportCanvas(canvas, 'res_scale').then(() => { 172*c8dee2aaSAndroid Build Coastguard Worker done(); 173*c8dee2aaSAndroid Build Coastguard Worker }).catch(reportError(done)); 174*c8dee2aaSAndroid Build Coastguard Worker })); 175*c8dee2aaSAndroid Build Coastguard Worker }); 176*c8dee2aaSAndroid Build Coastguard Worker }); 177*c8dee2aaSAndroid Build Coastguard Worker 178*c8dee2aaSAndroid Build Coastguard Worker}); 179