UNPKG

4.11 kBJavaScriptView Raw
1"use strict";
2
3var buffer = require("./buffer");
4
5function getContextForImage(image) {
6 var ctx;
7 buffer.makeBuffer(image.width, image.height, function(context) {
8 context.drawImage(image, 0, 0, image.width, image.height);
9 ctx = context;
10 });
11 return ctx;
12}
13
14/**
15 * A stretchable image that has borders.
16 * Similar to the [Android NinePatch]{@link https://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch}, but it only has the lines on the bottom and right edges to denote the stretchable area.
17 * A NinePatch is a normal picture, but has an extra 1-pixel wide column on the right edge and bottom edge. The extra column contains a black line that denotes the tileable center portion of the image. The lines are used to divide the image into nine tiles that can be automatically repeated to stretch the picture to any size without distortion.
18 * @constructor
19 * @alias Splat.NinePatch
20 * @param {external:image} image The source image to make stretchable.
21 */
22function NinePatch(image) {
23 this.img = image;
24 var imgw = image.width - 1;
25 var imgh = image.height - 1;
26
27 var context = getContextForImage(image);
28 var firstDiv = imgw;
29 var secondDiv = imgw;
30 var pixel;
31 var alpha;
32 for (var x = 0; x < imgw; x++) {
33 pixel = context.getImageData(x, imgh, 1, 1).data;
34 alpha = pixel[3];
35 if (firstDiv === imgw && alpha > 0) {
36 firstDiv = x;
37 }
38 if (firstDiv < imgw && alpha === 0) {
39 secondDiv = x;
40 break;
41 }
42 }
43 this.w1 = firstDiv;
44 this.w2 = secondDiv - firstDiv;
45 this.w3 = imgw - secondDiv;
46
47 firstDiv = secondDiv = imgh;
48 for (var y = 0; y < imgh; y++) {
49 pixel = context.getImageData(imgw, y, 1, 1).data;
50 alpha = pixel[3];
51 if (firstDiv === imgh && alpha > 0) {
52 firstDiv = y;
53 }
54 if (firstDiv < imgh && alpha === 0) {
55 secondDiv = y;
56 break;
57 }
58 }
59 this.h1 = firstDiv;
60 this.h2 = secondDiv - firstDiv;
61 this.h3 = imgh - secondDiv;
62}
63/**
64 * Draw the image stretched to a given rectangle.
65 * @param {external:CanvasRenderingContext2D} context The drawing context.
66 * @param {number} x The left side of the rectangle.
67 * @param {number} y The top of the rectangle.
68 * @param {number} width The width of the rectangle.
69 * @param {number} height The height of the rectangle.
70 */
71NinePatch.prototype.draw = function(context, x, y, width, height) {
72 x = x|0;
73 y = y|0;
74 width = width |0;
75 height = height |0;
76 var cx, cy, w, h;
77
78 for (cy = y + this.h1; cy < y + height - this.h3; cy += this.h2) {
79 for (cx = x + this.w1; cx < x + width - this.w3; cx += this.w2) {
80 w = Math.min(this.w2, x + width - this.w3 - cx);
81 h = Math.min(this.h2, y + height - this.h3 - cy);
82 context.drawImage(this.img, this.w1, this.h1, w, h, cx, cy, w, h);
83 }
84 }
85 for (cy = y + this.h1; cy < y + height - this.h3; cy += this.h2) {
86 h = Math.min(this.h2, y + height - this.h3 - cy);
87 if (this.w1 > 0) {
88 context.drawImage(this.img, 0, this.h1, this.w1, h, x, cy, this.w1, h);
89 }
90 if (this.w3 > 0) {
91 context.drawImage(this.img, this.w1 + this.w2, this.h1, this.w3, h, x + width - this.w3, cy, this.w3, h);
92 }
93 }
94 for (cx = x + this.w1; cx < x + width - this.w3; cx += this.w2) {
95 w = Math.min(this.w2, x + width - this.w3 - cx);
96 if (this.h1 > 0) {
97 context.drawImage(this.img, this.w1, 0, w, this.h1, cx, y, w, this.h1);
98 }
99 if (this.h3 > 0) {
100 context.drawImage(this.img, this.w1, this.w1 + this.w2, w, this.h3, cx, y + height - this.h3, w, this.h3);
101 }
102 }
103 if (this.w1 > 0 && this.h1 > 0) {
104 context.drawImage(this.img, 0, 0, this.w1, this.h1, x, y, this.w1, this.h1);
105 }
106 if (this.w3 > 0 && this.h1 > 0) {
107 context.drawImage(this.img, this.w1 + this.w2, 0, this.w3, this.h1, x + width - this.w3, y, this.w3, this.h1);
108 }
109 if (this.w1 > 0 && this.h3 > 0) {
110 context.drawImage(this.img, 0, this.h1 + this.h2, this.w1, this.h3, x, y + height - this.h3, this.w1, this.h3);
111 }
112 if (this.w3 > 0 && this.h3 > 0) {
113 context.drawImage(this.img, this.w1 + this.w2, this.h1 + this.h2, this.w3, this.h3, x + width - this.w3, y + height - this.h3, this.w3, this.h3);
114 }
115};
116
117module.exports = NinePatch;