Document directory
- 2. Method for Calculating the range of Path.
- 1. With such a framework, it is very easy to add new graphic elements, as is the image class.
For more information about the series of directories, see.
This section mainly solves three problems: finding the external rectangle of any geometric image. This external rectangle will be used in performance optimization. Of course, it is not only used in this aspect. Finally, the pressure test is performed on the optimized Renderer.
Let's go to the demo first, and the previous demo will scroll down and zoom in and out under firefox. The updated version can be used in ie9, chrome, and firefox (canvas is required ).
1. The first demo represents the external rectangle of the ry. We found that there is no external rectangle between the vertex and the image, because their range represents a vertex, both of which are center points.
Why is there no image range? The asynchronous image loading makes it impossible for us to know the width and height of the image from the very beginning.
Add point Add circle Add line Add a plane Tim Wuxing
2. the second demo is the performance test demo. clicking the test button will randomly Add 500 points and 500 five-pointed stars. You can click the button multiple times to add them, don't break your browser down ..).
We can find that the performance is quite good after we zoom in about 2 times, because we have made a small optimization here, through the external rectangle we obtained above and the range of the current view for intersection comparison, only the ry that matches the current view range is drawn.
Test adding 500 points and 500 pentagram
Well, after testing, do you have more confidence in canvas Vector Plotting? I still think that using canvas for vector graphics rendering is a BUG? I hope you can write your own opinions. Of course this is only a lot of preliminary performance optimization to be improved. 1. The following describes the external rectangle we mentioned above in detail.
In the Renderer, it is required that all the geometric types inherited from the geometry base class must have a method to calculate their range (getBounds). Of course, the calculation range is different for different geometric shapes.
1. Let's take a look at the simplest circle range calculation method.
Circle.prototype.getBounds = function () { if(!this.bounds) { this.bounds = new CanvasSketch.Bounds(this.x - this.radius, this.y - this.radius, this.x + this.radius, this.y + this.radius); return this.bounds; } else { return this.bounds; }}
As soon as you read the code, you will understand that this is not junior high school or elementary school mathematics ..
2. Method for Calculating the range of Path.
Currently, all geometric figures except point, circle, and img are directly inherited from the geometry base class and all others are inherited from line. In this way, we can solve all the problems as long as we get the line calculation range.
Line.prototype.getBounds = function () { if(!this.bounds) { var p0 = this.points[0]; this.bounds = new CanvasSketch.Bounds(p0.x, p0.y, p0.x, p0.y); for(var i = 1, len = this.points.length; i< len; i++) { var point = this.points[i]; var bounds = new CanvasSketch.Bounds(point.x, point.y, point.x, point.y); this.bounds.extend(bounds); } } return this.bounds;}
The line calculation range method is actually not difficult. We traverse all vertices and regard each vertex as a range. Using the bounds. extend method to combine all the ranges is the external rectangle we need.
The extend method is as follows:
CanvasSketch.Bounds.prototype.extend = function (bounds) { if(this.left > bounds.left) { this.left = bounds.left; } if(this.bottom > bounds.bottom) { this.bottom = bounds.bottom; } if(this.right < bounds.right) { this.right = bounds.right; } if(this.top < bounds.top) { this.top = bounds.top; }}
In this method, we compare the size and assign the appropriate location information to the bounds to be expanded.
The above two methods allow us to obtain the external rectangles of all the geometric shapes. Next we will discuss how to use the external rectangles to optimize the performance.
2. Renderer preliminary optimization.
This optimization is actually very simple, and it is also necessary for all graphics libraries to be optimized: to draw visible images, the rest will not be considered. This process is called "two-dimensional cropping" in graphics. If you are interested, you can use baidu.
With a range, we need a function to determine the intersection of two ranges:
CanvasSketch.Bounds.prototype.intersect = function (bounds) { var inBottom = ( ((bounds.bottom >= this.bottom) && (bounds.bottom <= this.top)) || ((this.bottom >= bounds.bottom) && (this.bottom <= bounds.top)) ); var inTop = ( ((bounds.top >= this.bottom) && (bounds.top <= this.top)) || ((this.top > bounds.bottom) && (this.top < bounds.top)) ); var inLeft = ( ((bounds.left >= this.left) && (bounds.left <= this.right)) || ((this.left >= bounds.left) && (this.left <= bounds.right)) ); var inRight = ( ((bounds.right >= this.left) && (bounds.right <= this.right)) || ((this.right >= bounds.left) && (this.right <= bounds.right)) ); intersects = ((inBottom || inTop) && (inLeft || inRight)); return intersects;}
Through this function, we can determine whether the two ranges are mutually exceeded. The following formal optimization begins:
Canvas.prototype.redraw = function(){ this.context.clearRect(0, 0, this.layer.size.w, this.layer.size.h); var geometry; if(!this.lock){ for(var id in this.geometrys){ geometry = this.geometrys[id][0]; var bounds = geometry.getBounds(); if(this.layer.bounds.intersect(bounds)) { style = this.geometrys[id][1]; this.draw(geometry, style, geometry.id); } } } }
Before drawing a graph, we can determine whether the range exists with the current view range. If the range exists, we can draw a graph without any intersection.
In this way, our basic optimization is finished, and we plan to have more advanced optimization later. We are still considering the solution.
3. Adding images is supported. 1. With such a framework, it is very easy to add new graphic elements, as is the image class.
// CLASS: display image CLASS. Function Img (point, image) {Geometry. apply (this, arguments); this. point = point; if (typeof image = Image) {this. useUrl = false; this. image = image;} else {this. useUrl = true; this. image = image ;}} Img. prototype = new Geometry (); Img. prototype. geoType = "Img"; Img. prototype. getBounds = function () {return new CanvasSketch. bounds (this. point. x, this. point. y, this. point. x, this. point. y );}
You can directly input an image object (provided that the request has been completed ). We can also pass in the image url to request images internally. After the request is complete, the image will be set as a resource of the Img object, you do not need to request again later.
2. Add the corresponding resolution image for rendering.
// Image Rendering Method. Canvas. prototype. drawImage = function (geometry, style, id) {var canvas = this; if (! Geometry. useUrl) {var img = geometry. image; imageLoad ();} else {var img = new Image (); img. onload = imageLoad; img. loadErro = imageErro; img. src = geometry. image;} function imageLoad () {canvas. setCanvasStyle ("fill", style); var fixedSize = style. fixedSize; var pt = canvas. getLocalXY (geometry. point); var width = style. width | img. width; var height = style. width | img. height; if (fixedSize) {var offsetX = width/2; var offsetY = height/2; canvas. context. drawImage (img, pt. x-offsetX, pt. y-offsetY, width, height);} else {var res = canvas. layer. getRes (); var offsetX = width/2/res; var offsetY = height/2/res; canvas. context. drawImage (img, pt. x-offsetX, pt. y-offsetY, width/res, height/res);} if (geometry. useUrl) {geometry. useUrl = false; geometry. image = img;} canvas. setCanvasStyle ("reset");} function imageErro (){}}
Here we use a small closure technique. We use the local variable canvas to save the reference to this (this has already pointed to the image itself after the image is loaded ).
After adding an image loading completion event, we first draw the image to the canvas (Here we add a style attribute: fixedSize; If fixedSize is set to true, we will not resize the image ).
Save the image as a resource.
In this way, our image class is created.
Two essays were written in one day. The next essay will bring you some advanced applications: two-and three-dimensional integration-the two-dimensional 3D interchange of geometric graphics through our designed Renderer (PS. since it has not been implemented yet, the encoding cycle may grow a little longer, so stay tuned ~)
Try: Download the source code this time and modify the demo to open it. Can there be any new discoveries (bugs? Haha ~)
Next notice: 1. 2D and 3D integration of vector graphics.
For all the source code + demo in this essay, please click to download.