Restrict an object to stay within another object - javascript

This is related to SVG, I have a large SVG object made of paths which stays static. With a press of a button, I can create another SVG object inside the larger object. The second object can be dragged with the mousedown.
PROBLEM:
Now I want to add a restriction so that the second object created cannot venture outside of the main object.
I tried using 'mouseup' for restriction but that does not work because the restriction is applied according to the cursor point on the second object, rather than the border of the second object.
Hope someone can help.
UPDATE:
#Phrogz : We have been trying to get Kevin's code to work but are struggling to get any results. We have a function attached to onmouseup to find out the intersected points of the object on the underneath path.
The function is suppose to give the results of the intersection & give an alert that the function has been exected. Its not giving anything in response, leading us to wonder whether the function is being executed at all.
Here is the main code:
var path=svgDoc.getElementById("path");
var str=intersectPathShape(path,DragTarget);
alert(str)
Phrogz, any thoughts on this?

You will need to use an intersection library like this one by Kevin Lindsey to detect when the paths overlap and prevent it. (He also provides demos of his code.)
Depending on how you implement your dragging, you may also need to check the bounding box of the two items to ensure that one is contained in the other (since dragging the child completely outside the parent would cause them not to intersect, but also not be a legal position).
The simplest code would be to store the last position of the child and return it to that position when an intersection is detected. Under fast dragging, though, this might cause the child to stop being dragged at a spot that is not actually touching. For a better user experience, you may want to try a binary search of intermediary offsets between the last known-good position and the current position to find the closest point along that path that is legal.

Kayote,
I think I answered this in another question. The short version is have a look at this github project:
https://github.com/thelonious/js-intersections
In particular, the loadShapes function in this file:
https://github.com/thelonious/js-intersections/blob/master/samples/IntersectionUtilities.js
You will need to instantiate a specific object per node type then pass those to Intersection.intersectShapes.
HTH,
Kevin

Related

How can I limit an overlay to a specific range?

I want to add an overlay to my editor that will only apply in a given range (e.g. from line 3, column 44 to line 8, column 5).
The problem is that I couldn't come up with any way to find what the current line is in my token() method, since overlays are stateless, so I can't store the current line in the state.
I pored over the extensions in multiplex.js and overlay.js, and tried to grok how nested modes work, but I could not figure out a way to use any of these tools to help me here. Keep in mind I still want this to behave like an overlay, so without disturbing the base mode.
My alternative is to scan elements for the added class and manually modify them, using element.getBoundingClientRect() and cm.coorsChar() to check their position. But this is ugly, needs manual refreshing, and causes bugs when marked elements span across my range boundaries. Any idea on how to solve this properly?
You can't bound an overlay like that. But you also don't have to manually mess with the dom. The markText method provides a more convenient way to style specific pieces of your document.

Mouseover d3.js map with different layers

I made my TopoJSON with 3 different administrative levels. During mouseover, I would like the object from Level 2 to be highlighted. However, due to layering, the object could only detect the mouse event if there is no object above it (from, let's say, Level 3). It's a javascript issue, I could simply change the z-index of each levels (either by CSS or in the script). I also tried reordering the calls for each level. However, I read somewhere that d3.js has it's own way of processing the objects, so the approaches I mentioned didn't seem to work.
How do I make sure that the object that I want stays on top?
For some reason, what worked for me is FIRST adding the object with the event listener. AND make sure that the object's fill color exists (not set to none).

Polygon mouseover event position

There is a problem on my website. I need to capture "mousemove" event and after that change the position of hint window according to the position of cursor at the moment of event. Here is the code:
google.maps.event.addListener(country, 'mousemove', function(e) {
this.setOptions({fillOpacity: 1});
$('div.info-win').css('top', e.kb.clientY + 20 + 'px');
$('div.info-win').css('left', e.kb.clientX -50 + 'px');
$('div.info-win').show()
});
At first everything was ok, but soon browser started to show the error, that e.kb is not defined. I checked the event via console and realized that "e.kb" really does not exist. Instead there was "e.lb" so I changed it in my code. But now the problem is the same, and console shows me that "e.lb" does not exist. I cant explain it, but now the captured event has ".gb" property instead of ".lb". can someone help me and explain why this happens every week again , so I need always to check the name of event property?? this is the first time I see problem like that but at the same time I cannot find any solution!
The Google Maps MouseEvent doesn't give the screen X and Y values.
Instead, it seems to give only Latitude/Longitude of the mouse position.
Reference:
https://developers.google.com/maps/documentation/javascript/reference#MouseEvent
https://developers.google.com/maps/documentation/javascript/reference#PolyMouseEvent
You need to convert the Latitude/Longitude value to the screen mouse X/Y position which is explained here (similar question):
Get Position of Mouse Cursor on Mouseover of Google Maps V3 API Marker
The reason your map worked for a while and later started failing is that you are using undocumented properties of the MouseEvent object. As you discovered, these may change at any time.
Think about it: do kb and lb and gb sound like names you would use in your code to describe a mouse position? And would you change them willy-nilly like that? :-)
So why does Google use gibberish names like these, and why do they change them all the time?
In the original source code that their developers work on, of course they use readable and consistent names. But then they compile the code with a "minifier" that shortens the private variable/property/method names for faster loading. When they revise the source and recompile it, those short names get reassigned arbitrarily.
The three different property names you found over the weeks clearly all refer to the same object in the original source, but the minifier changed the name you see in the browser.
Never assume you can use a property or method you discover in your browser's developer tools - especially if it has a name that makes no sense. Check it first in the Maps API documentation, and if it's not there, don't use it.
See Seyong's answer for the details of how to change your code to use the documented methods.

Setting the Location of Groups

A newbie question. As I've explained in a prior post, I'm coming to SVG Land from Flash loaded with ActionScript expectations and misconceptions.
I've built an interactive graphic using D3 and I'm nearly finished except that I want to add a little pop-up box that displays when a user mouses over a state. Right now it appears as a static object labeled "West Virginia" on the left side of the stage:
http://www.50laboratories.com/miscellany/demographicclout2.html
The pop-up is a group with its own distinct ID. I need to be able to set its x and y location depending on the state being hovered over, but so far can't figure out how. It seems to me that I should be able to address a group in my JavaScript as I would a named movie clip in Flash, but visiting API references like this one, https://github.com/mbostock/d3/wiki/API-Reference, I see no references to methods and properties of group objects. Thanks in advance for your help.
Unlike actionscript, svg elements are dom nodes and manipulating them involves either setting their attributes or style properties. You could manipulate these by calling certain attribute/style setters of the dom nodes, but since you're using d3, you set those attributes/styles using d3's setters.
The way to position a element with d3 is to
1. select it, by the id you assigned it
2. set its transform attribute to translate([some-x], [some-y])
d3.select("#statepopup").attr("transform", "translate(50,100)");
P.S.
The transform attribute is also how you can scale and rotate the group.

iOS-style formatting callout using Rangy

I'm looking at Rangy (http://code.google.com/p/rangy/) and it seems it has a bunch of DOM utilities but I don't understand them without examples. So I'm turning to SO with my ideas and hopefully you guys can show me how this can be done:
What I need to do with Rangy is use it to find the position and dimensions of the selection. I want to get the frame or Rect of the selection, whether relative to the document or parent element. Then I can position my callout accordingly.
I believe the demo that comes with Rangy already illustrates what you want. specifically http://rangy.googlecode.com/svn/trunk/demos/position.html inside showSelectionPosition function
Considering the fact that selection may be spread across multiple elements, it'd be best to use the coordinates of either startSelEl or endSelEl to anchor your callout to the beginning or end of a selection.
There is an embryonic, unreleased Rangy module I wrote for getting pixel coordinates of a selection or range. Unfortunately the difficulty of getting this working properly in all browsers and all situations has put me off completing it and I have essentially abandoned it. However, if you add a bit more detail about what you're trying to do I may be able to suggest something.

Categories

Resources