Dart SVG Drag and Drop Slipping Mouse - html

I try to create drag and drop behavior in Dart using SVG. I have BasicUnits that are basically GElement (<g>)s. Right now it has a body, which is a RectElement. I am using that element to move the unit around. Here is the definition:
class BasicUnit {
SvgSvgElement canvas;
GElement group;
RectElement body;
bool dragging;
num dragOffsetX, dragOffsetY, width, height;
BasicUnit(SvgSvgElement this.canvas, num x, num y, num this.width, num this.height) {
this.body = new RectElement();
this.body.setAttribute('x', '$x');
this.body.setAttribute('y', '$y');
this.body.setAttribute('width', '$width');
this.body.setAttribute('height', '$height');
this.body.classes.add('processing_body');
this.body.onMouseDown.listen(select);
this.body.onMouseMove.listen(moveStarted);
this.body.onMouseUp.listen(moveCompleted);
this.body.onMouseLeave.listen(moveCompleted);
this.group = new GElement();
this.group.append(this.body);
this.dragging = false;
}
void select(MouseEvent e) {
e.preventDefault();
this.dragging = true;
var mouseCoordinates = getMouseCoordinates(e);
this.dragOffsetX = mouseCoordinates['x'] - body.getCtm().e; //double.parse(body.attributes['x']);
this.dragOffsetY = mouseCoordinates['y'] - body.getCtm().f;
}
void moveStarted(MouseEvent e) {
e.preventDefault();
if (dragging) {
var mouseCoordinates = getMouseCoordinates(e);
num newX = mouseCoordinates['x'] - dragOffsetX;
num newY = mouseCoordinates['y'] - dragOffsetY;
this.body.setAttribute('transform', 'translate($newX, $newY)');
}
}
void moveCompleted(MouseEvent e) {
e.preventDefault();
this.dragging = false;
}
dynamic getMouseCoordinates(e) {
return {'x': (e.offset.x - this.canvas.currentTranslate.x)/this.canvas.currentScale,
'y': (e.offset.y - this.canvas.currentTranslate.y)/this.canvas.currentScale};
}
}
I have an Application object. It gets the svg element for given id. Here is the definition:
class Application {
int WIDTH = 80, HEIGHT = 60;
SvgSvgElement canvas;
Application(canvas_id) {
this.canvas = document.querySelector(canvas_id);
this.canvas.onDoubleClick.listen((MouseEvent e) => addUnit(e));
}
void addUnit(MouseEvent e) {
num x = e.offset.x - WIDTH/2;
num y = e.offset.y - HEIGHT/2;
BasicUnit newUnit = new BasicUnit(this.canvas, x, y, WIDTH, HEIGHT);
this.canvas.append(newUnit.group);
}
}
My problem is that my mouse is slipping over BasicUnit or <g> element. When you select the element close to its edges and try to drag, suddenly element gets dropped. If you try to drag and drop fast, that is the case as well. I tried to follow the example on this webpage, but couldn't figure out what the problem is.
UPDATE
Full source code available here.
UPDATE II
Here is a demo.

The browser is trying to drag the text around that is selected after you double click on the page. This can be fixed easily by preventing the default behaviour for the onMouseDown event (your select method):
void select(MouseEvent e) {
e.preventDefault();
this.dragging = true;
this.group.parentNode.append(this.group);
var mouseCoordinates = this.getMouseCoordinates(e);
this.dragOffsetX = mouseCoordinates['x'] - this.body.getCtm().e;
this.dragOffsetY = mouseCoordinates['y'] - this.body.getCtm().f;
}
The other problem is caused by the svg not drawing fast enough to keep up with the mouse coordinates. So, when moved fast enough the mouse coordinates move outside the body of the SVG element, so the element will no longer get mouse move events. This can be solved by listening for the onMouseMove and onMouseLeave events on the background SVG element (canvas in your example) instead of the elements being moved:
body.onMouseDown.listen(select);
canvas.onMouseMove.listen(moveStarted);
body.onMouseUp.listen(moveCompleted);
canvas.onMouseLeave.listen(moveCompleted);
EDIT:
Using the above method works unless the onMouseUp occurs when the element being dragged is underneath another element, in which case the element is still being dragged until another onMouseUp event occurs on that element, or the cursor moves outside of the viewing area. This can be fixed by just listening for onMouseUp events on the canvas instead of body:
canvas.onMouseUp.listen(moveCompleted);
See this example.
Additionally it might be better to turn on the onMouseMove, onMouseUp, and onMouseLeave listeners when the element is clicked (in your select method), then disable the listeners on onMouseUp and onMouseLeave (the moveCompleted method). I have done this in the example above.

Related

Flash Senocular Transform Tool - controls are not showing on the tool

I am having trouble with the controls showing up for my transform tool. When I click my image I get the bounding box (to scale or rotate the image), but when I hover over the corner I do not get the cursor to transform it.
I am using these files:
TransformTool.as
TransformToolControl.as
TransformToolCursor.as
This is my code to call the transform tool:
var tool:TransformTool = new TransformTool();
addChild(tool);
And this later on to make the tool show up when the image is clicked and make the tool disappear when the stage is clicked:
tmpImage.addEventListener(MouseEvent.CLICK, select);
function select(e:MouseEvent):void {
tool.target = e.currentTarget as Sprite;
stage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
My image selection for the bounding box to appear and disappear work perfectly. All my code works as expected.... except the actual controls on the bounding box. Please help!
Edit
The concept is the user can click an image from a menu and drag a new instance of that image to the stage. Then the user can click the new instance and should be able to rotate or scale it. Then they can click off the image to make the bounding box disappear. (They can add as many images to the stage that they want).
Here is some code that shows the basic click, create new instance, and drag process I have implemented.
//sb1 is the menu area that contains a group of images
//hill is one of the images the user can add to the stage
sb1.hill.addEventListener(MouseEvent.MOUSE_DOWN, createCopy);
var i:int=0;
var tmpImage:Sprite; //to store which image is being dragged currently
function createCopy(e:MouseEvent):void {
tmpImage = new Hill_mc();
tmpImage.name = "hillChild"+(i++); //increment every copy
container.addChild(tmpImage);
tmpImage.x = mouseX-470;
tmpImage.y = mouseY-270;
tmpImage.startDrag();
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, onDown); //add the mouse down to this new object
stage.addEventListener(MouseEvent.MOUSE_UP, onUp); //since the mouse is currently down, we need to listen for mouse up to tell the current copy to stop dragging
}
//this will be called when click a copy
function onDown(e:MouseEvent):void {
tmpImage = Sprite(e.currentTarget); //get a reference to the one that was clicked, so we know which object to stop dragging on the global mouse up.
container.addEventListener(MouseEvent.MOUSE_UP, onUp); //listen for the mouse up
tmpImage.startDrag();
}
function onUp(e:MouseEvent):void {
container.removeEventListener(MouseEvent.MOUSE_UP,onUp);
if (tmpImage.hitTestObject(thesubmenu1)) {
container.removeChild(tmpImage);
}
else {
tmpImage.stopDrag();
}
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
function select(e:MouseEvent):void {
tool.target = e.currentTarget as Sprite;
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
EDIT
I found this code and placed it in my TransformTool.as. I feel like it's so close and that there must be something called incorrectly because I get an error for a null object reference:
public function select(event:Event):void {
// the selected object will either be the
// event target or current target. The current
// target is checked first followed by target.
// The parent of the target must match the
// parent of the tool to be selected this way.
if (event.currentTarget != this
&& event.currentTarget.parent == parent){
setTarget(event.currentTarget as DisplayObject, event);
}else if (event.target != this
&& event.target.parent == parent){
setTarget(event.target as DisplayObject, event);
}
}
/**
* Helper selection handler for deselecting target objects. Set this
* handler as the listener for an event that would cause the
* deselection of a target object.
* It is not required that you use this event handler. It is only a
* helper function that can optionally be used to help ease
* development.
*/
public function deselect(event:Event):void {
if (_target != null && event.eventPhase == EventPhase.AT_TARGET){
setTarget(null, null);
}
}
You give too little information to determine what exactly is wrong.
However, there is a very good sample code that does exactly what you want here :
http://www.senocular.com/demo/TransformToolAS3/TransformTool.html
(Click on the link at the bottom of the image.)
I am sure that you are going to make it with this.
EDIT :
Try to use the built-in handlers. I would do something like this :
Instead of this :
tmpImage.addEventListener(MouseEvent.CLICK, select);
function select(e:MouseEvent):void {
tool.target = e.currentTarget as Sprite;
stage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}
Do this :
tmpImage.addEventListener(MouseEvent.MOUSE_DOWN, tool.select);
stage.addEventListener(MouseEvent.MOUSE_DOWN, tool.deselect);
EDIT :
If you do not have the handlers, I am not sure :) but I would recommand removing event listeners in each method as they might be interfering with each other.
tmpImage.addEventListener(MouseEvent.CLICK, select);
function select(e:MouseEvent):void {
tmpImage.removeEventListener(MouseEvent.CLICK, select);
tool.target = e.currentTarget as Sprite;
stage.addEventListener(MouseEvent.MOUSE_DOWN, deselect);
}
function deselect(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_DOWN, deselect);
tool.target = null;
tmpImage.addEventListener(MouseEvent.CLICK, select);
}

Changing text dynamically with drag / drop in Flash CS6 (AS3)

I have some incredibly simple code that works fine in letting me drag a "slider" button horizontally. However, I also want the text that appears above the object to change depending upon what the x-coordinate is of the object I'm dragging.
Here's the simple code:
var rectangle:Rectangle = new Rectangle(31,944,179,0);
Button.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag);
function fl_ClickToDrag(event:MouseEvent):void
{
Button.startDrag(false, rectangle);
}
Button.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
function fl_ReleaseToDrop(event:MouseEvent):void
{
Button.stopDrag();
gotoAndPlay(20);
}
What I'm wanting to do is have the system determine where the "Button" is in terms of its x-coordinate, and if the x-coordinate is higher than, say, 50, for the text above the "Button" to say "50+", and if the x-coordinate is higher than 100 for the text to change to "100+". I'm also not sure if the x-coordinate should be relative to the rectangle or relative to the entire screen.
Any and all help is appreciated.
You can use a boolean var to indicate if your button is dragged and if, then update your text field like this :
var is_dragged:Boolean = false;
var rectangle:Rectangle = new Rectangle(0, 100, stage.stageWidth - button.width, 0);
stage.addEventListener(Event.ENTER_FRAME, _onEnterFrame);
function _onEnterFrame(e:Event):void {
if(is_dragged){
text_field.text = String(Math.round(button.x / 50) * 50) + '+';
}
}
button.addEventListener(MouseEvent.MOUSE_DOWN, button_onPress);
function button_onPress(e:MouseEvent):void {
button.startDrag(false, rectangle);
is_dragged = true;
}
button.addEventListener(MouseEvent.MOUSE_UP, button_onRelease);
function button_onRelease(e:MouseEvent):void {
button.stopDrag();
is_dragged = false;
}
You can see this code working here.
Hope that can help.

Problems with AS3 scrollbar script

I have this symbol for a scrollbar in adobe flash:
The instance name of the dark part is handle, and that of the lighter bar is bar. The symbol is an instance of the Scroll class:
package ui {
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class Scroll extends MovieClip{
public static const VERTICAL = 0;
public static const HORIZONTAL = 1;
protected var _handleRatio = 1;
protected var _orientation = VERTICAL;
protected var _mousePrevPos:int;
protected var _handleMargin:int;
protected var _container:MovieClip;
protected var _containerInitialPosition:int; //added after update #2
public function Scroll(container:MovieClip, visibleLength:int, orientation:int = VERTICAL) {
_orientation = orientation;
_container = container;
var containerLength:int;
switch(_orientation){
case VERTICAL:
rotation = 0;
containerLength = container.height;
_containerInitialPosition = container.y; //added after update #2
break
case HORIZONTAL:
rotation = - 90;
containerLength = container.width;
_containerInitialPosition = container.x; //added after update #2
break;
default:
throw new Error('Unknown orientation');
break;
}
if((_handleRatio = visibleLength/containerLength) > 1)
_handleRatio = 1;
handle.height = _handleRatio*height;
_handleMargin = handle.y;
handle.addEventListener(MouseEvent.MOUSE_DOWN, _startDrag, false, 0, true);
}
protected function _startDrag(e:MouseEvent){
stage.addEventListener(MouseEvent.MOUSE_UP, _stopDrag, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_MOVE, _dragHandle, false, 0, true);
_mousePrevPos = mouseY;
}
protected function _stopDrag(e:MouseEvent = null){
stage.removeEventListener(MouseEvent.MOUSE_UP, _stopDrag);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, _dragHandle);
_mousePrevPos = NaN;
}
protected function _dragHandle(e:MouseEvent){
_moveHandle(mouseY - _mousePrevPos);
_mousePrevPos = mouseY;
}
protected function _moveHandle(moveDifference:int){
if(moveDifference > 0 && !(handle.y + handle.height + _handleMargin > bar.height)){
if(!(handle.y + handle.height + moveDifference + _handleMargin > bar.height))
handle.y = handle.y + moveDifference;
else
handle.y = bar.height - handle.height - _handleMargin;
}
if(moveDifference < 0 && !(handle.y < _handleMargin)){
if(!(handle.y + moveDifference < _handleMargin))
handle.y += moveDifference;
else
handle.y = _handleMargin;
}
switch(_orientation){
case VERTICAL:
_container.y = _containerInitialPosition -((handle.y-_handleMargin)/(bar.height-_handleMargin*2)*_container.height);
// since update #2, the calculated y position is subtracted from the initial y position
break
case HORIZONTAL:
_container.x = _containerInitialPosition -((handle.y-_handleMargin)/(bar.height-_handleMargin*2)*_container.width);
// since update #2, the calculated x position is subtracted from the initial x position
break;
default:
throw new Error('Unknown orientation');
break;
}
}
public function resize(newWidth, newHeight){
switch(_orientation){
case VERTICAL:
width = newWidth;
height = newHeight;
break
case HORIZONTAL:
rotation = 0;
width = newHeight;
height = newWidth;
rotation = -90;
break;
default:
throw new Error('Unknown orientation');
break;
}
}
public function scrollHandle(e:MouseEvent){
_moveHandle(-e.delta);
}
}
}
As you can see, you can create both horizontal and vertical scrollbars. Now, there are two problems with the scrollbar:
For some reason, when dragging the handle up/left with the mouse, the handle moves far slower than the cursor
Also, when you scroll a horizontal scrollbar a little to the right, the left part of the container is cut off, and you can't scroll back to it anymore solved now, see update #2
I really don't know what causes these problems, so can anyone please help me or at least point out where the errors in my code are?
Update
Some extra information to help explain the code:
This is a sketch of a situation where a vertical scrollbar would be needed. The scrollbar would be initiated like so:
var scrollBar:Scroll = new Scroll(container, mask.height, Scroll.VERTICAL);
When the handle of the scrollbar is dragged/scrolled down, the container is moved upwards, so that you get to see a lower part of the contaienr - and vice versa: if you scroll up, the container is moved down.
If you'd want to create a horizontal scrollbar, apart from changing Scroll.VERTICAL into Scroll.HORIZONTAL, you'd pass mask.width as visibleLength instead of mask.height.
I suppose container doesn't neccessarily have to be a MovieClip but can be any DisplayObject.
Also, I'm not using startDrag() so that I can drag the handle and scroll the handle up and down with just one method (_moveHandle()).
Update #2
I solved problem #2: the left part of the container was cut off because when the container hadn't been scrolled yet, the container's x position was somewhere in the middle of the stage. When it was scrolled a little bit to the right, I forgot to set the container's x position to the calculated x position + the initital x position. I updated the code above, with comments behind the new parts so you can see what I changed.
Update #3
You can see a flash file making use of the scrollbar here: http://host.undeadzone.net/scrollBarTest.swf
To reproduce issue #1, do the following:
grab the handle with the mouse and slowly drag the slider down, one notices that the mouse position relative to the slider stays constant. (if you clicked at the top most edge of the handle to start dragging, the mouse will still be at the top most edge when the handle reaches the bottom of the screen. this is the expected behaviour, all good.
Now do the opposite (it doesn't matter if you release the mouse
after doing step 1) and drag the handle upwards slowly. This time,
the position of the mouse relative to the handle changes. If one initiated the drag at the top most edge of the handle and starts
dragging up, the handle does not keep up with the mouse and the
mouse position (relative to the handle) will be above the handle
after dragging, even though it started the dragging within the
handle.
The source code:
http://host.undeadzone.net/scrollBarTest.zip
To fix 1-st issue add e.updateAfterEvent:
protected function _dragHandle(e:MouseEvent){
_moveHandle(mouseY - _mousePrevPos);
_mousePrevPos = mouseY;
e.updateAfterEvent();
}
UPDATE
mouseY returns Number not int.
Replace this line:
protected var _mousePrevPos:int;
with this:
protected var _mousePrevPos:Number;
in Scroll class.
UPDATE #2
Replace
protected function _moveHandle(moveDifference:int){
with
protected function _moveHandle(moveDifference:Number){

Path glow effect in the mouse over event in actionscript 3

I'm building a board game in action script 3 Adobe flash. In that if i mouseover on a particular pawn, it has to show the number of steps which can be moved by that pawn with respect to dice value with path glow effect.
Here in my code path will glow after i move the pawn with respect to dice number.
opawn1.addEventListener(MouseEvent.CLICK, fl_ClickToGoToAndStopAtFrame_3);
function fl_ClickToGoToAndStopAtFrame_3(event: Mouse): void {
var filterarray: Array=new Array();
opawn1.filters=[glow];
var gfilter: GlowFilter=new GlowFilter();
filterarray.push(gfilter);
current_pawn = arrayPawn[0];
checkSize(opawn1);
if (o_move == 0) {
o_move = 1;
convert_to_movieclip(s1);
}
temp = get_number_of_moves(odirectmove, checkorange, 0, current_pawn);
odirectmove = false;
for(var i=0;i<temp+1;i++)
{
s1[i].filters=filterarray;
}
Here I used mouse click event, Its not working if i change it as mouseover.
Please let me know the above code is correct or not.
How to achieve this?
As #otololua said, the type of your fl_ClickToGoToAndStopAtFrame_3 event parameter should be MouseEvent and not Mouse, then you can change MouseEvent.CLICK by MouseEvent.MOUSE_OVER like this :
opawn1.addEventListener(MouseEvent.MOUSE_OVER, opawn1_on_MouseOver);
function opawn1_on_MouseOver(event:MouseEvent): void {
var glow_filter: GlowFilter = new GlowFilter();
var filters_array: Array = [glow_filter];
your_target_object.filters = filters_array
// ...
}
And if you need that effect be visible only when the mouse is over, you can remove it using MouseEvent.MOUSE_OUT like this :
opawn1.addEventListener(MouseEvent.MOUSE_OUT, opawn1_on_MouseOut);
function opawn1_on_MouseOut(event:MouseEvent): void {
your_target_object.filters = null;
// ...
}
Hope that can help you.

JTabbedPane: Attach mouse listener to the part of the tab-select UI that doesn't contain the tabs

This is in conjunction to the question posed here:
JTabbedPane: Components before and after the tabs themselves
I want to attach a mouse listener that allows for dragging the constructed google chrome-like frame. Starting out, the initial dragging code is rather easy, and the mouse-dragging code at this Kirill-post can be used pretty much directly. I'd only want this behaviour if the user clicks and drags on the "title bar" of the frame, that is, the area where the tabs (the stick-uppers) reside. This is also easy - just change the dragging code to only accept clicks in the upper area of the JTabbedPane, the part that contains the tabs.
However, I want to reduce the grabbable area further, and only allow click-and-drag-frame in the area NOT occupied by the tabs (the stick-uppers - anyone have a better name for this GUI element?) - again quite like Google Chrome (Chrome also adds a bar above the tabs when in windowed mode, to easier get hold of the frame if many tabs are active. But Chrome do this perfect: It is possible to grab the window in the tabbed part that doesn't have tabs, and even in the small v's inbetween the tabs!)
What I'd effectively want to do, is to be able to attach the mouse listeners to the background of the GUI for the tabs - but how to accomplish something like this?
After looking at the solutions for this question (draggable tabs in Swing), I found that the actual TabbedPaneUI has some methods that can fix both problems: Only drag window in tab area, which turned out to be the hardest part, and not drag when above the tabs themselves. The relevant code follows, in the two sections marked with "// ::". The code is adapted from the question-mentioned Kirill-code. The code doesn't handle other cases than when the tabs are at top - which makes sense when considering what I want to do.
// mouse listener for dragging the host window
MouseAdapter adapter = new MouseAdapter() {
int lastX;
int lastY;
boolean _dragInitiated;
#Override
public void mousePressed(MouseEvent e) {
TabbedPaneUI ui = _windowTabs.getUI();
// :: Won't drag if we're positioned above a tab in tab area
if (ui.tabForCoordinate(_windowTabs, e.getX(), e.getY()) != -1) {
_dragInitiated = false;
return;
}
// :: Won't drag if we're below the tab area
int maxY = 0;
for (int i = 0; i < _windowTabs.getTabCount(); i++) {
Rectangle bounds = ui.getTabBounds(_windowTabs, i);
int y = bounds.y + bounds.height;
if (y > maxY) {
maxY = y;
}
}
_dragInitiated = true;
if (maxY > 0) {
if (e.getY() > maxY) {
_dragInitiated = false;
}
}
Point eventLocationOnScreen = e.getLocationOnScreen();
if (eventLocationOnScreen == null) {
Component source = (Component) e.getSource();
eventLocationOnScreen = new Point(e.getX() + source.getLocationOnScreen().x, e.getY()
+ source.getLocationOnScreen().y);
}
lastX = eventLocationOnScreen.x;
lastY = eventLocationOnScreen.y;
}
#Override
public void mouseDragged(MouseEvent e) {
if (!_dragInitiated) {
return;
}
Point eventLocationOnScreen = e.getLocationOnScreen();
if (eventLocationOnScreen == null) {
Component source = (Component) e.getSource();
eventLocationOnScreen = new Point(e.getX() + source.getLocationOnScreen().x, e.getY()
+ source.getLocationOnScreen().y);
}
int dx = eventLocationOnScreen.x - lastX;
int dy = eventLocationOnScreen.y - lastY;
Window win = POTabbedFrame.this;
Point loc = win.getLocation();
win.setLocation(loc.x + dx, loc.y + dy);
lastX = eventLocationOnScreen.x;
lastY = eventLocationOnScreen.y;
}
};
_windowTabs.addMouseListener(adapter);
_windowTabs.addMouseMotionListener(adapter);