I have built an ASP.NET MVC application which will render a floor plan in SVG after a user selects a specific buildling and floor. Using Timmywil's panzoom library, I've added the ability for users to move the floor plan around and zoom in or out on it. The floor plan is initially rendered in the center of the screen and the zoom is adjusted so the whole floor plan is visible.
Via a button, users can save the floor plan in PDF format. After this button click, the SVG tag with the paths inside is used as input to convert it. However, only the initial situation is saved since the viewbox and coordinates are still the same. I've used Timmywil's samples to demonstrate my problem. Below is the initial situation. So the floor plan (in this case a lion) is nicely centered and fully visible inside of the div (the black bordered box):
In the situation a floor plan is really large and a user would only like to have a certain part of saved (picture 2 and 3), it should 'crop' the SVG, but I'm having trouble finding the numbers and making the calculations to achieve this. I guess it has to be done by changing the viewbox values.
Could someone help me out?
Related
I have a slider/guage/bar component to select a value. As the slider is dragged it updates a value to give the user feedback:
currentValue = Math.round((componentHeight - draggedValue) / componentHeight * vesselVolume);
The slider gives its value from the top position of an absolute div inside an overflow hidden div parent, giving the illusion of a gauge that can be raised and lowered.
This all works fine.
The problem
I'm using the gauge to estimate the volume of liquid in a vessel. If the vessel has level, straight edges, fine, but it may not. A barrel, for example, will bulge out then back in.
I can use a mask over my guage to simulate the vessel being filled but it made me wonder if the task of being able to extract some some of volume filled of the vessel shown is ridiculously complicated or something approachable?
My current approach
I'll be using my own SVG graphics which could provide simple line data. I'm looking into whether there's a clipping or boolean operation possible on SVGs in vanilla javascript where I can clip the graphic where the top of the gauge reaches.
I presume I could then calculate the area of the resulting graphic, and present a volume of liquid if provide the volume of liquid that would have fit in the entire vessel.
I'm providing no depth information but it's currently safe for me to assume all vessels are symmetrical around the Y axis.
I'm a bit clueless at math involving shapes, is this task feasible? As a compromise, I would be ok to use crude formula that emulate various vessels if they approximately simulate edges diverging at a certain angle up to a certain height, etc.
Edit 2: I found what I was looking for here. The near and far planes compound the bounding box of the camera.
I have a Perspective Camera and multiple set of points (SphereGeometry) in the space and I want to define a bounding box according to what is visible in the field of view, so that I only need to load the points that are currently visible in the space according to the camera settings.
My problem when defining the bounding box is that I don't have a reference point between the camera position and what I'm currently looking at. For example, if the camera is at the position v1(20, 20, 20), and let's say the mid point of my set of points is set at v2(5, 5, 5). Then, I can define the initial point of my bounding box as this mid point v2(5, 5, 5) , and I could create a bounding box (square) with size (v1-v2)/2. But once I start moving the camera I lose this reference initial point, and I don't know how to obtain a distance parameter to define a proper bounding box of "what is currently visible".
Every time I move the camera I need to know the size of the bounding box and its position so that it represents as accurate as possible "what is currently visible" in the field of view.
One possible solution could be to translate the initial point v2(5, 5, 5) following every camera movement, is there any way to do this or something similar?
Edit:
So far I've been able to replicate #TheJim01 's code into my component, but I think this solution is not what I was looking for or I'm not able to understand it properly. I'm adding some images next to better explain what is going on.
In the next image I have a set of points of various colors, the 8 brown points represent each of the worldBoxCorners before performing a worldToLocal transformation. Which fits the whole space as it should.
Next, I render worldBoxCorners after the transformation. I do not understand how the bounding box is moved or how can I use it.
What I'm looking for is, for example if I zoom in into the space in the greener zone, to obtain a bounding box alike the last image.
The point is to only load the points that are within the field of view, but for that I need to define a bounding box. When I say loading the points, I mean that only the points that are visible should be loaded from the backend (not talking about rendering here).
This solution provides a perfect bounding box for the current loaded space. What I'm missing on is how to define a new bounding box for a given loaded space according to camera parameters change (zoom in/out or rotations).
I am writing an app that uses Highcharts, and in one instance I want to have a "slider" at the bottom of the chart that extends up vertically over the chart. Moving the slider will update other parts of the page based on where the user moves the slider on the chart.
The problem is that when drawing anything on top of the Highchart (image or a div) the performance becomes absolutely unacceptable. The slider simply cannot keep up with the mouse movements See a jsfiddle here. Note - this only happens when working with a large number of data points (which is absolutely unavoidable in my case).
Is there anything that I can do, short of not drawing on top of the chart?
I suspect the slowness is because the browser has to redraw the chart (either the whole thing or parts of it) as the div slides over it. With a large data set to redraw the chart from, this becomes annoyingly slow.
There are solutions, but not all of them are always acceptable:
You can try reducing the number of points in your data set by sampling it at a lower rate.
You can try windowing, so that the viewer only shows a range within the entire set. For example, if you have 10,000 data points your window can slide along the data set, showing only 1,500 points at a time as opposed to all 10,000 points.
Move to a different technology such as Flash or Silverlight.
Like I said, though, not all of these or even any of them will work for you.
I noticed that when you drag the slider over the graph it still highlights the datapoints. You probably should set pointer-events:none on that part of your chart while dragging the slider, that will allow browsers to not check pointer-events in that subtree (which if you have a lot of datapoints can be somewhat expensive, especially if you update these elements on hover).
I'm currently working on an interface where I have a primary canvas that is 800x800 in size. At the top I've generated a bunch of icons. When a user mouses over the icons at the top, it matches his mouse's x and y coordinates to determine if he is currently hovering over any of the icons. If he is, I want to have a hover effect where a label appears next to the mouse with the name of the icon. As he moves, the label follows the mouse. If he leaves the icon or moves to a different one, the last one is cleared, and either there is no label displayed (if the user moved off all icons), or another label is displayed next to the mouse in the last one's place (if he hovers over another icon, the width of the label is a variable length depending upon the width of the text).
The process of ordering and displaying these icons all occurs within a separate object from the rest of the canvas renderings, thus I wouldn't exactly want to re-render that entire object to display the icons every time a mousemove event triggers, so I'm wondering if there's a way to draw to another "temporary" canvas' context and whether or not that could be easily cleared. as the mouse moves so there isn't any trails left behind on the primary canvas? Can anyone point me in the direction of an example like this or advise me on how I should go about accomplishing this sort of task?
Yes you can certainly draw it onto a temporary (in-memory) canvas. This is done a lot of various reasons, and yours may be valid (especially if you don't have any background that changes). But it may not be the easiest to implement, its hard to say without knowing more about your app.
There's a decent alternative you should consider: you could have two canvases that are 800x800 in size overlaid atop each-other. This can be useful for some applications (like games) where there is a background, foreground, and middle-ground that all have different moving parts (but the background parts move rarely, and foreground isn't always present, etc)
In the same way, you could "layer" your canvas app, with the icons being on one canvas, and the background and other parts of the app being on the other canvas.
I'm working on an app that displays a large image just about the same way as Google Maps. As the user drags the map, more images are loaded so that when a new part of the map is visible, the corresponding images are already in place.
By the way, this is a Javascript project.
I'm thinking of representing each tile as a square div with the image loaded as a background image.
My question: how exactly can I calculate what divs are showing, and when the tiles are moved, how do I tell when a new row of divs have become visible?
Thanks!
About calculating what divs are showing: learn the algorithm for intersecting two rectangles (the stackoverflow question Algorithm to detect intersection of two rectangles? is a good starting point). With that, the divs that are showing are the ones whose intersection with the "view window" is non-empty.
About telling when a new row of divs have become visible: you will probably need a updateInterface() method anyway. Use this method to keep track of the divs showing, and when divs that weren't showing before enter the view window, fire a event handler of sorts.
About implementation: you should probably have the view window be itself a div with overflow: hidden and position: relative. Having a relative position attribute in CSS means that a child with absolute position top 0, left 0 will be at the top-left edge of the container (the view area, in your case).
About efficiency: depending on how fast your "determine which divs are showing" algorithm ends up being, you can try handling the intersection detection only when the user stops dragging, not on the mouse move. You should also preload the areas immediately around your current view window, so that if the user doesn't drag too far away, they will already be loaded.
Some further reference:
Tile5: Tiling Interfaces
gTile: Javascript tile based game engine
Experiments in rendering a Tiled Map in javascript/html…
There's no reason to implement this yourself, really, unless it's just a fun project. There are several open source libraries that handle online mapping.
To answer your question, you need to have an orthophoto-type image (an image aligned with the coordinate space) and then a mapping from pixel coordinates (i.e. the screen) to world coordinates. If it's not map images, just arbitrary large images then, again, you need to create a mapping between the pixel coordinates of the source image at various zoom levels and the view-port's coordinates.
If you read Google Map's SDK documentation you will see explanations of these terms. It's also a good idea to explore one of the aforementioned existing libraries, read its documentation and see how it's done.
But, again, if this is real work, don't implement it yourself. There's no reason to.