UNPKG

4.28 kBJavaScriptView Raw
1var buffer = require("./buffer");
2
3function getContextForImage(image) {
4 var ctx;
5 buffer.makeBuffer(image.width, image.height, function(context) {
6 context.drawImage(image, 0, 0, image.width, image.height);
7 ctx = context;
8 });
9 return ctx;
10}
11
12/**
13 * A stretchable image that has borders.
14 * 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.
15 * 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.
16 * @constructor
17 * @alias Splat.NinePatch
18 * @param {external:image} image The source image to make stretchable.
19 */
20function NinePatch(image) {
21 this.img = image;
22 var imgw = image.width - 1;
23 var imgh = image.height - 1;
24
25 var context = getContextForImage(image);
26 var firstDiv = imgw;
27 var secondDiv = imgw;
28 var pixel;
29 var alpha;
30 for (var x = 0; x < imgw; x++) {
31 pixel = context.getImageData(x, imgh, 1, 1).data;
32 alpha = pixel[3];
33 if (firstDiv === imgw && alpha > 0) {
34 firstDiv = x;
35 }
36 if (firstDiv < imgw && alpha === 0) {
37 secondDiv = x;
38 break;
39 }
40 }
41 this.w1 = firstDiv;
42 this.w2 = secondDiv - firstDiv;
43 this.w3 = imgw - secondDiv;
44
45 firstDiv = secondDiv = imgh;
46 for (var y = 0; y < imgh; y++) {
47 pixel = context.getImageData(imgw, y, 1, 1).data;
48 alpha = pixel[3];
49 if (firstDiv === imgh && alpha > 0) {
50 firstDiv = y;
51 }
52 if (firstDiv < imgh && alpha === 0) {
53 secondDiv = y;
54 break;
55 }
56 }
57 this.h1 = firstDiv;
58 this.h2 = secondDiv - firstDiv;
59 this.h3 = imgh - secondDiv;
60}
61/**
62 * Draw the image stretched to a given rectangle.
63 * @param {external:CanvasRenderingContext2D} context The drawing context.
64 * @param {number} x The left side of the rectangle.
65 * @param {number} y The top of the rectangle.
66 * @param {number} width The width of the rectangle.
67 * @param {number} height The height of the rectangle.
68 */
69NinePatch.prototype.draw = function(context, x, y, width, height) {
70 x = Math.floor(x);
71 y = Math.floor(y);
72 width = Math.floor(width);
73 height = Math.floor(height);
74 var cx, cy, w, h;
75
76 for (cy = y + this.h1; cy < y + height - this.h3; cy += this.h2) {
77 for (cx = x + this.w1; cx < x + width - this.w3; cx += this.w2) {
78 w = Math.min(this.w2, x + width - this.w3 - cx);
79 h = Math.min(this.h2, y + height - this.h3 - cy);
80 context.drawImage(this.img, this.w1, this.h1, w, h, cx, cy, w, h);
81 }
82 }
83 for (cy = y + this.h1; cy < y + height - this.h3; cy += this.h2) {
84 h = Math.min(this.h2, y + height - this.h3 - cy);
85 if (this.w1 > 0) {
86 context.drawImage(this.img, 0, this.h1, this.w1, h, x, cy, this.w1, h);
87 }
88 if (this.w3 > 0) {
89 context.drawImage(this.img, this.w1 + this.w2, this.h1, this.w3, h, x + width - this.w3, cy, this.w3, h);
90 }
91 }
92 for (cx = x + this.w1; cx < x + width - this.w3; cx += this.w2) {
93 w = Math.min(this.w2, x + width - this.w3 - cx);
94 if (this.h1 > 0) {
95 context.drawImage(this.img, this.w1, 0, w, this.h1, cx, y, w, this.h1);
96 }
97 if (this.h3 > 0) {
98 context.drawImage(this.img, this.w1, this.w1 + this.w2, w, this.h3, cx, y + height - this.h3, w, this.h3);
99 }
100 }
101 if (this.w1 > 0 && this.h1 > 0) {
102 context.drawImage(this.img, 0, 0, this.w1, this.h1, x, y, this.w1, this.h1);
103 }
104 if (this.w3 > 0 && this.h1 > 0) {
105 context.drawImage(this.img, this.w1 + this.w2, 0, this.w3, this.h1, x + width - this.w3, y, this.w3, this.h1);
106 }
107 if (this.w1 > 0 && this.h3 > 0) {
108 context.drawImage(this.img, 0, this.h1 + this.h2, this.w1, this.h3, x, y + height - this.h3, this.w1, this.h3);
109 }
110 if (this.w3 > 0 && this.h3 > 0) {
111 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);
112 }
113};
114
115module.exports = NinePatch;