Find-replace on canvas - javascript

I have an image with flags on it like the one with a pie chart here .
How can I find a particular flag on it and replace with another flag using canvas?
Edit:
I cannot control the source image, but the region to find is always known and the image to replace is always the same size as the one to find. I just need to replace one particular flag with another particular flag.
Edit 2:
The flag may appear in the image several times.

You won't see spectacular performance, but one way to approach this is by just iterating over the pixels in your pie chart image.
Call getImageData() on your pie chart image to acquire all the pixel data for the image (ie. request the maximum dimensions). Similarly, call getImageData() on the flag you want to search for. Setup a loop that iterates over all the pixels acquired from the pie chart. For each pixel, assume it is the top left (or another corner based on your iteration order) of the flag you are searching for. Compare it to the first pixel in your flag pixel data, and if they agree, continue iterating within a window size equal to the width and height of your flag. If you get to the end of the window iteration and each pixel pair matches, you've found the flag you're looking for. If they don't, move on to the next pixel in the pie chart data and iterate over the window again.
Note that in the worst case you're looking at O([N * W * H] - [W * H]) or just O(N * W * H) with N = pie chart pixels and W x H = flag dimensions. You could probably improve this by not iterating over windows where you know there will be no flags, and by shifting the window more intelligently. Once you do find a match, you have the coordinates of the corner where you want to call drawImage() to paste your new flag on top.
Of course this approach assumes that the flag you're searching for is represented exactly in the pie chart image. If you are comparing a non-compressed flag to a compressed pie chart image, or vice versa, you won't find a match. Likewise, any size or orientation variations will completely defeat this approach. If you need that kind of flexibility, you're delving into something like SIFT territory. While I'm sure that could be implemented using canvas elements, I wouldn't want to be the one to do it.
In this situation, you'll want to make sure that you don't traverse the DOM unnecessarily while performing iterations. In particular, you will want to store local references to the pixel data as explained here: http://www.onaluf.org/en/entry/13

Given you already know the coordinates and have an image to map, you'll likely want to use drawImage.

Related

d3 y Domain and Range

I need to find out where to draw my y axis dependent of a date
My data looks like the following in .csv format:
startYYYYMM, endYYYYMM, ProjectName
201301, 201303, Proj1
201302, 201412, Proj2
201304, 201311, Proj3
I've done the chart as laying bar chart
Where to start my bars on the x axis is dependent on the start and is no problem. It's the y that is the problem.
I wonder If there is any built in "optimization" in d3 that I can use. I release that I can loop through my data to decide "the grouping" of my data.
And a pic of how I would like it to look like:
https://www.dropbox.com/s/5xs0jfxb33ipn60/temp.jpg
/Thank's
If I understand correctly, the difference between what you want and a standard Gantt chart is that the Gantt chart puts every project on its own line, but you want to compact the display so that long-finished projects don't continue to take up a row of blank space.
To get that "optimized function based on date" that figures out where on the Y-domain you can fit a project to keep the display compact, you're going to need to keep track of which projects are active at a given time, and loop through them to find out where you have room on your display for a new project.
Here's an algorithm you could implement. The results won't always be perfect (sometimes a small rectangle will end up taking up room in a space where a larger rectangle could have been positioned) but it should be much more compact than a standard Gantt chart.
Sort your projects by start date and work through them in that order, assigning y-positions to each.
As you work through your project list, keep a secondary array of "active" projects -- ones that have been started but not finished at the time you are looking. These will always be projects that you have already positioned on the graph, since you're positioning projects in order of start time.
For each project in your main array:
go through the active-project array (if it's not empty) and remove any projects that finished before the project you are plotting started (if you want padding between rectangles, require a certain minimum time to have passed in between);
sort the active-project array by the y-position you have already assigned to each project-rectangle;
scan through the active-project array, checking the y-position and height of each rectangle, to see if you have room to place the rectangle for your current project;
if you can't fit it in-between any of the currently active projects, set it's position to be above the last active project, and check whether the new position+height of this rectangle exceeds your previous maximum height;
either way, store the calculated y position (which will be in the same units as the variable you are using for rectangle height) in the project's data-object.
Now that you've set this project's position, add it to the active-project array and move on to the next project in your main array.
Once you have determined a relative y-position for each rectangle, set your y-scale domain according to the maximum height you used and draw the axis and rectangles.
You can look at this answer for some inspiration, although that example is more complicated than what you need.

Javascript canvas and optimization of internal functions?

Say I have a rectangle that is 100 x 100 and I have a canvas 1000 x 1000.
As long as the rectangle's x co-ordinate is no more than 999 and no less than -100, it is true to say that some portion of the rectangle will be visibly seen on the canvas. Same goes for the rectangle's y co-ordinate.
What I would like to know is that if the rectangle's x or y co-ordinate is set so that the rectangle will not be visible on the canvas, does the internal workings of the canvas api still draw the rectangle or does it auto optimize and realise by itself that the bitmap that will be drawn on the canvas will not be seen, so therefore it doesn't attempt to draw it.
When drawing to canvas the boundaries are checked for each draw. If a pixel ends up outside the canvas it is clipped (discarded).
If not you would get a memory corruption and very soon a crash.
Canvas is designed to be very safe so you won't have poorly written Javascripts (intentional or not) crashing your browser. The same applies to colors where color values (f.ex. using a bitmap array directly) are clamped to be within the valid range.
Optimization is dependent on the implementation, but it's reasonably to assume that if the area is completely outside the boundaries of the canvas, the draw operation is rejected in full. If it is partly inside it may start the internal block copy by moving start and end cursor to represent the effective area that would be rendered visible.
The other option is to check each pixel as it is rendered, if it's inside or outside the visible boundary. This however is not optimal.
To visualize, only the gray areas would be considered, the light-blue would be ignored:
(I didn't show all possibilities but it should be easy to imagine the bottom parts etc.)
Cursor here is where the internal routine will start and stop looping through the pixels. In this case if the area to be drawn is 100x100 pixels and is drawn at -50, -50 (x,y) then the internal cursor is set to +50, +50 relative to the area being drawn and the width and height is reduced likewise.
By moving the cursor and adjusting the width and height, it doesn't have to iterate through all the pixels and therefor optimizes the copy (although, it is not quite accurate to say "all pixels", as data is not copied per pixel but mainly on block basis related to memory alignment. There are separate algorithms that deals with optimized memory copying and takes into account offset bytes (bytes that does not start or end on a "clean" memory boundary) and so forth, ie. 4 or 8 bytes are copied in one go rather than one and one byte combined with masking (AND'ing the bits)).
The boundaries apply to lines and circles etc. as well. Their effective drawing area is handled as a square area, but there are different approaches to draw lines, circles than a square of pixels, to optimize further.
See f.ex. Bresenham algorithm for lines or mid-point circle algorithm for circles or various algorithms for ellipses - I don't the specific implementation in each browser, but for these you square of the start and end coords and in some cases (as with circles and ellipses) you may have to check as you go (perhaps drawing the circle in four parts and check the part which is overlapping the boundaries on a pixel-individual basis - this is implementation specific though).
When it comes to translation that is merely a recalculation of coordinates (translate, rotation using rotation matrixes and stuff like that). The new coordinates are then checked against boundary.
Now that being said it is not sure the browsers have their own specific implementation. They might use the system's native bitmap and clipping functionality instead where possible. However, the same described above applies in this case as well.
FWIW, On IE, Chrome and FF the fully offscreen draws (non-draws?) took about 100ms less than onscreen draws for 100,000 rects.
According to the canvas spec:
"When the destination rectangle is outside the destination image (the scratch bitmap), the pixels that land outside the scratch bitmap are discarded, as if the destination was an infinite canvas whose rendering was clipped to the dimensions of the scratch bitmap."
This is not absolutely specific to your question but it's likely all "out of canvas view" operations are handled this way. So based on that, I'd say Yes, they are "optimised".

determine efficiently which rectangle a point is in 2d space

I have a large set of rectangles that are drawn on html5 canvas.
I would like to be able to interact with this image using mouse tracking (I cannot use SVG because it does not scale to 10-100k rectangles). Is there any data structure/algo that, given the mouse x,y coordinates would be able to tell you which box the mouse was over (using the computed locations of the rectangles)? I was thinking something like a k-d tree but was not sure.
If your data is always of the form shown I think you should be able to do better than a spatial tree data structure.
Since the data is structured in y you should be able to calculate which 'strip' of rectangles the points is in based on offsets in O(1) time.
If you store the individual rectangles within each 'strip' in sorted order (using xmax say) you should then be able to locate the specific rectangle within the strip using a binary search (in O(log(n))).
Hope this helps.
The naive solution would be to iterate over all rectangles and check if you are in it. Checking for a single rectangle is easy (if you want I will write it down explicitly).
If you have many rectangles and care about performance, you can easily speed things up by putting the rectangles in a data structure which is faster to look in. Looking at the image you sent, one obvious property of your data is that there is a limited amount of vertical positions ("rows"). This means that if you check which row you are on, you then only need to check rectangles within that row. Finally, to select which row you are on or within a row select which rectangle, keep a sorted data structure (e.g. some search tree).
So your data structure could be something like a search tree for row, where each node holds a search tree of rectangles along the row.
R-tree is suitable for providing spatial access of this kind
But some questions:
Is your rectangle set static or dynamic?
How many point queries do you expect for rectangle set?
Edit:
Because rectangle set is static:
There is method, used in traditional graphics with bitmaps (don't know is it applicable to html5 canvas or not):
Make additional bitmap with the same size as main picture. Draw every rectangle with the same coordinates, but fill it with unique color (for example, color = rectangle index). Then check color under mouse point => get rectangle index in O(1)

Draw Zoomable Time Line With Scroll Bars On Html5 Canvas

I need a Time Line For My Web Project.
Something like this - I read the code of this Time Line but did not understand it because it is not documented enough.
My problem is the math behind all of this (not the interaction with the canvas).
I have read several articles about the math of the scroll bars, but none of them talk about zoom.
Some
articles suggest to hold canvas element with very large width value - and to display just the
View Port.
I don't think that's the right way to do it - I want to draw just the correct viewport.
In my project, I have array of n points.
Each point holds time value represented in seconds, but not all of the points are within the Viewp Port.
Considering the current zoom level, how do I calculate:
What points should be drawn and where to draw them?
What is the size and position of the thumb?
Any articles / tutorials about such a thing?
You might be able to use something like Flot which handles the placement of points, as well as zooming and panning. Here's an example of that.
There are a bunch of other drawing libraries, here a good list.
You always have Raphealjs.com , one of the most used library to play with SVG, with this you can write your own js to generate the timeline.

RaphaelJS -- vector or not?

I'm trying to place a circle at 50% of the width of the paper using RaphaelJS, is this possible without first doing the math (.5 * pixel width)? I want to simply be able to place an element at 50% of its container's width, is this even possible with the current Raphael API?
Raphael claims to be able to draw vector graphics, and yet it seems everything in the API is pixel-based. How can you draw a vector image using pixels? That seems 100% contradictory.
Likewise, as I understand vector art, it retains the same dimensions regardless of actual size. Is this not one of the primary reasons to use vector graphics, that it doesn't matter if it's for screen, print or whatever, it will always be the same scale? Thus, I'm further
confused by the need for something like ScaleRaphael; just seems like such functionality is part and parcel to creating vector graphics. But, perhaps I just don't understand vector graphics?
It just doesn't seem like an image that is created with absolute pixel dimensions and unable to be resized natively qualifies as a vector image. That, or I'm missing a very large chunk of the API here.
Thanks in advance for any help. I've attempted to post this twice now to the RaphaelJS Google Group, but I guess they are censoring it for whatever reason because I've been waiting for it to appear since last week and still no sign of my posts (although other new posts are showing up).
Using pixel values to define shape positions/dimensions does not make it a non-vector shape. Take for instance Adobe Illustrator - this is a vector product and yet you can still see that the properties for each object shows the positions and dimensions is pixels.
A basic explanation of vector graphics would be like this, taking a rectangle as an example:
A vector rectangle will have a number of properties such as x, y,
width and height. These properties can be specified in pixels. The
difference with vector (as opposed to raster) is that these pixel
properties are only used to determine how the shape is drawn. So when
the display is rendered (refreshed) the "system" can redrawn the shape
using the same properties without effecting the quality of the resize.
A raster image however will hold a lot more information (i.e. the
exact value of each pixel used to form the shape/rectangle)
If the word "pixel" makes you think it is contradictory, just remeber everything on a computer screen is rendered in pixels. Even vector graphics have to be converted to "raster" as some point in the graphics pipeline.
If you are worried about having to use a calculation (0.5 * width) then just remember that something has to do that calculation, and personally I would happily handle this simple step myself.
After all that, you should just calculate size and position in pixels based on the size of your "paper" element and feed those values in Raphael for creating the shape.

Categories