Copy link to clipboard
Copied
Since I read that HTML5 Canvas doesn't support 9-slice scaling, I thought I'd code it myself. I use two rectangles (rect_horiz and rect_vert) and four circles (corner_0, corner_1 etc.), and the shapes overlap, and should theoretically produce a pretty rounded rectangle. It seems to almost work, but I'm getting weird inaccuracies in the graphics, on the top and left edges (the bottom right corner came out as hoped).
To keep this post simple, here is just the code for rect_horiz (the rectangle that stretches across the entire width of the rounded rectangle I'm trying to create) and corner_0 (the top left corner). The movie clip roundRect contains these two movie clips. In the library, the circle is exactly 50 px across, and the rectangle is exactly 10px x 10px. Neither one has a stroke.
The idea in this example is to create a rounded rectangle programmatically with width 500 and height 100. Again, this is just a piece of the code, but if it worked correctly, in the resulting graphics (green shapes shown in screenshot from browser, below), the left edge of the rectangle should be flush with the left edge of the circle. Instead, the circle sticks out to the left by several pixels. (The same problem occurred with rect_vert which I had intended to fill the top white gap, but I omitted that rect here for brevity).
(Note: "fixOrigin" follows the recommended method to deal with the problem that "CreateJS returns Transformation Point in instead of movieclip's x,y properties" (https://community.adobe.com/t5/animate-discussions/createjs-returns-transformation-point-in-instead-...and that approach has worked fine for me elsewhere.)
I feel like there must be some kind of rounding error in how the scaling is being applied here? Is there a way to fix this problem?
var width = 500;
var height = 100;
var cornerRadius = 25;
var unitSize = 10;
fixOrigin(this.roundRect);
fixOrigin(this.roundRect.rect_horiz);
fixOrigin(this.roundRect.corner_0);
this.roundRect.rect_horiz.x = 0;
this.roundRect.rect_horiz.y = cornerRadius;
this.roundRect.rect_horiz.scaleX = width/unitSize;
this.roundRect.rect_horiz.scaleY = (height - 2 * cornerRadius) / unitSize;
this.roundRect.corner_0.x = 0;
this.roundRect.corner_0.y = 0;
function fixOrigin (mc) {
mc.x -= mc.regX;
mc.y -= mc.regY;
mc.regX = 0;
mc.regY = 0;
}
Hi.
Congrats on your progress.
Alternatively, have you tried the ScaleBitmap class?
http://blog.createjs.com/scaling-and-stretching-with-the-scalebitmap-class/
Please let us know.
Regards,
JC
Copy link to clipboard
Copied
Well, here's an idea. Instead of two overlapping rectangles, I'll try it with 6 rectangles (plus the 4 circles to make the rounded corners). One rectangle for each edge, plus another big rectangle for the center of the rounded rectangle. This will be more cumbersome code and presumably will require more processing, but hopefully won't be as buggy...
Copy link to clipboard
Copied
If anybody is curious, that second method (dividing up into actually 5 rectangles) works pretty well. At first there were "cracks" of white showing through, because the bug in scaling is still there. But I was able to cover it up using a "fudge factor" of 0.65 which expands the middle rectangle slightly. The cracks start to show through if the rectangle is too large.
So, there really seems to be some kind of bug wherein scaling by a large amount shifts the movie clip over. I'd love to know if there's a direct fix for that.
Here's my 9-slice scaling code, for anyone who's interested. The circles are now 20px across, and the squares are still 10px x 10px.
var width = 326; // arbitrary dimensions for rounded rectangle
var height = 197;
var cornerRadius = 10;
var unitSize = 10;
fixOrigin(this.roundRect);
fixOrigin(this.roundRect.rect_top);
fixOrigin(this.roundRect.rect_right);
fixOrigin(this.roundRect.rect_bottom);
fixOrigin(this.roundRect.rect_left);
fixOrigin(this.roundRect.rect_middle);
fixOrigin(this.roundRect.corner_0);
fixOrigin(this.roundRect.corner_1);
fixOrigin(this.roundRect.corner_2);
fixOrigin(this.roundRect.corner_3);
this.roundRect.rect_top.x = cornerRadius;
this.roundRect.rect_top.y = 0;
this.roundRect.rect_top.scaleX = (width - 2 * cornerRadius) / unitSize;
this.roundRect.rect_top.scaleY = 1;
this.roundRect.rect_right.x = width - cornerRadius;
this.roundRect.rect_right.y = cornerRadius;
this.roundRect.rect_right.scaleX = 1;
this.roundRect.rect_right.scaleY = (height - 2 * cornerRadius) / unitSize;
this.roundRect.rect_bottom.x = cornerRadius;
this.roundRect.rect_bottom.y = height - cornerRadius;
this.roundRect.rect_bottom.scaleX = (width - 2 * cornerRadius) / unitSize;
this.roundRect.rect_bottom.scaleY = 1;
this.roundRect.rect_left.x = 0;
this.roundRect.rect_left.y = cornerRadius;
this.roundRect.rect_left.scaleX = 1;
this.roundRect.rect_left.scaleY = (height - 2 * cornerRadius) / unitSize;
this.roundRect.rect_middle.x = 0.65 * cornerRadius; // 0.65 is probably not the optimal value, but it worked for me
this.roundRect.rect_middle.y = 0.65 * cornerRadius;
this.roundRect.rect_middle.scaleX = (width - 2 * 0.65 * cornerRadius) / unitSize;
this.roundRect.rect_middle.scaleY = (height - 2 * 0.65 * cornerRadius) / unitSize;
this.roundRect.corner_0.x = 0;
this.roundRect.corner_0.y = 0;
this.roundRect.corner_1.x = width - 2 * cornerRadius;
this.roundRect.corner_1.y = 0;
this.roundRect.corner_2.x = width - 2 * cornerRadius;
this.roundRect.corner_2.y = height - 2 * cornerRadius;
this.roundRect.corner_3.x = 0;
this.roundRect.corner_3.y = height - 2 * cornerRadius;
function fixOrigin (mc) {
mc.x -= mc.regX;
mc.y -= mc.regY;
mc.regX = 0;
mc.regY = 0;
}
Copy link to clipboard
Copied
Aha, I found a better fix. I was able to make it work with my original method (just 2 rectangles overlapping like a Swiss cross, plus the 4 circles for corners). Simply start with really huge squares, like 1000px x 1000px. So unitSize = 1000, using my original code in the OP. Lo and behold, the scaled shapes line up perfectly, no doubt because any "error" in the positioning of the scaled shapes is trivial in comparison to their starting size.
Copy link to clipboard
Copied
Hi.
Congrats on your progress.
Alternatively, have you tried the ScaleBitmap class?
http://blog.createjs.com/scaling-and-stretching-with-the-scalebitmap-class/
Please let us know.
Regards,
JC
Copy link to clipboard
Copied
Thank you so much! I will have a look at this.
Lesson learned. I only searched within this forum and found nothing so I assumed it was up to me to build from scratch. It's a good reminder that really, what I am doing is building with EaselJS, and Animate (for HTML5 Canvas) is simply a tool to make that easier.
Copy link to clipboard
Copied
You're welcome!
Yeah, the people behind CreateJS has lots of stuff on their blog, GitHub, CodePen, JSFiddle, and other places.
Copy link to clipboard
Copied
Find more inspiration, events, and resources on the new Adobe Community
Explore Now