Normally, drag and drop are done using 2 elements.
But, what if I have a dynamic grid, and I want to select a part of it by click-hold and dragging it then release. (similar to drag and drop)
I was able to get the x and y coordinates already, but I am not sure how to make it work without an element.
It looks like an element is required.
After using the element (body), I was able to make drag and drop work.
var offsetx = dndoffset.x;
var offsety = dndoffset.y;
browser.waitForAngular();
this.getTargetIndex(<ObjectToBeDragged>,function (targetIndex) {
var targetElement = element.all(by.repeater(<ng-repeat value>)).get(targetIndex);
targetElement.getLocation().then(function (location) {
offsetx = Math.round(offsetx + location.x);
browser.actions().mouseMove(<ObjectToBeDragged>)
.mouseDown()
.mouseMove(targetElement)
.mouseMove(targetElement, {x: offsetx, y: offsety})
.mouseUp().perform();
});
browser.waitForAngular();
});
The above is the snippet I am using to drag and drop. You always have element in the DOM (even it is dynamic). You have to pick the right one and place it there.
Since we have the ng-repeat, we are using by.repeater() to locate the element dynamically.
Related
I am using Adobe Captivate to produce an online learning activity, We are using the drag and drop which works well. Only issue is that it is not dynamic, therefore once a student has got it correct they can just follow position to get correct again.
Is it possible to shuffle the position of drag or drop objects so as to show that the sudent has understanding of the question and not just following a remembered pattern.
Not out of the box. There's no like "Shuffle Drag Sources" checkbox like there is for say multiple choice answers. It would be possible to achieve something like you are asking by putting this script into your OnEnter action and selecting "Execute Javascript":
$(function () {
var dss = cp.DD.CurrInteractionManager.m_ActiveInteraction.m_dsList;
var ypos = dss.map((i) => {
return $("div[id='" + i.n + "']").css("top");
});
ypos = shuffle(ypos);
dss.forEach((o, i) => {
$("div[id='re-" + o.n + "c']").css("top", ypos[i]);
$("div[id='" + o.n + "']").css("top", ypos[i]);
});
function shuffle(arr) {
for (var i = 0; i < arr.length; i++) {
var randId = Math.floor(Math.random() * arr.length);
var tmp = arr[i];
arr[i] = arr[randId];
arr[randId] = tmp;
}
return arr;
}
});
I didn't put comments in here for copy/paste purposes because that awful Captivate JavaScript window is very flaky with whitespace, so a statement by statement walkthrough is here:
var dss = cp.DD.CurrInteractionManager.m_ActiveInteraction.m_dsList;
Collects all of the drag sources into an array.
var ypos = dss.map((i) => {return $("div[id='" + i.n + "']").css("top")});
Extracts the Y position of each object.
ypos = shuffle(ypos);
Calls the function (defined below) to shuffle the order of the array of Y positions randomly.
dss.forEach((o, i) => {$("div[id='re-" + o.n + "c']").css("top", ypos[i]);
$("div[id='" + o.n + "']").css("top", ypos[i]);});
Cycles through the drag sources and places each into its new position, bringing the canvas along with it.
Couple of caveats here.
If more than one attempt is allowed, the "Reset button will place the
drag sources back to their original locations.
This assumes the drag sources are all lined up with the same
horizontal position. If they are scattered about, the X position
would also need to be accounted for.
I didn't test this on a responsive or flex project, I'm not sure how Adobe does the positioning for object in those cases, this will work on fixed-sized projects.
Arrow functions might not be supported in IE11, if you need to support that, you might need to re-write the callback functions using traditional syntax.
I have a script which handles many sprite arrays. I didn't want to drag them one by one so I wrote a CustomEditor for it that can allow me to assign multiple sprites at once using drag and drop operation:
[CustomEditor(typeof(MyMonoBehaviour))]
public class MyMonoBehaviourEditor : Editor
{
Sprite[] sprites;//actually Sprite[,][] but simplified here
Object[] DropAreaGUI()
{
Event evt = Event.current;
Rect drop_area = GUILayoutUtility.GetRect(0.0f, 20.0f, GUILayout.ExpandWidth(true));
GUI.Box(drop_area, "Drop here!");
switch (evt.type)
{
case EventType.DragUpdated:
case EventType.DragPerform:
if (!drop_area.Contains(evt.mousePosition))
return null;
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
if (evt.type == EventType.DragPerform)
{
DragAndDrop.AcceptDrag();
return DragAndDrop.objectReferences;
}
break;
}
return null;
}
void OnInspectorGUI(){
var drops = DropAreaGUI();
if (drops != null)
{
//the following line gives me error
sprites = drops.Select(x => (x as Sprite)).ToArray();
}
}
}
I lock the inspector, select 12 sprites from Project, drag them onto the box and when I drop them it gives me this error: ArgumentException: GUILayout: Mismatched LayoutGroup.DragPerform
I noticed that DragAndDrop.objectReferences returns an Object[] which is in my case a Texture2D[] and I can't cast it to Sprite[]. I tried Sprite.Create but it asks for rect and pivot which I don't have.
How can I make DragAndDrop recognize that I am dropping Sprites and not Texture2Ds?
If you're trying to assign multiple sprites to an array in the inspector, you can actually just drag and drop them onto the array itself.
What you'd typically do is select the asset you want to drag them into, then click the padlock in the upper-right of the inspector to lock it. Then you can select multiple objects and drag them onto the array itself (the name of the array with the drop-down menu) rather than into any particular slot of the array. Unity will then automatically populate the array with what you dropped there.
This works with arrays and lists (and possibly other container types, if unity displays them in the inspector).
I found the workaround.
instead of return DragAndDrop.objectReferences; I wrote return DragAndDrop.paths;
and then loading is possible:
sprites = drops.Select(x => AssetDatabase.LoadAssetAtPath<Sprite>(x)).ToArray();
I have just started unity. I have 4 Images(sprites) aligned in a grid.
As soon as i touch the particular chocolate, its texture changes[I wrote a code for that]. There is a button on screen.After pressing the button, I want to move only those chocolates whose texture has been changed.
I know the following move code but i don't know how to use it here.
void Update () {
float step=speed*Time.deltaTime;
transform.position=Vector3.MoveTowards(transform.position,target.position,step);
}
I just don't know to move that particular sprite whose texture is changed. Thanks
Do you want to be moving the sprites over the course of a duration or instantly?
If it's over the course of a duration I suggest you use Lerp. You can Lerp between two Vector.3's in a time scale. Much cleaner and once learned a very useful function.
Code examples below:
http://docs.unity3d.com/ScriptReference/Vector3.Lerp.html
http://www.blueraja.com/blog/404/how-to-use-unity-3ds-linear-interpolation-vector3-lerp-correctly
However if you want to move it instantly. This can be done very easily using the built in localPosition properties which you can set in or outside the object.
Set your changed sprites Bool moved property (create this) to true on click (if you're using Unity 4.6 UI canvas then look at the IClick interfaces available for registering mouse activity in canvas elements) and then when you press the button, loop through a list in a handler file which contains all your button texture objects and move those that the moved property is set to true for.
foreach(GameObject chocolate in chocolateList)
{
if (chocolate.moved == true)
{
gameObject.transform.localPosition.x = Insert your new x position.
gameObject.transform.localPosition.y = Insert your new y position.
}
}
However please do clarify your intentions so I can help further.
EDIT 1:
I highly suggest you make your sprites an object in the canvas for absolute work clarity. This makes a lot of sense as your canvas can handle these type of things much better. Use Image and assign your image the sprite object (your chocolate piece), define it's width and height and add a script to it called "ChocolatePiece", in this script create two public variables, bool moved and int ID, nothing else is required from this script. Save this new object as your new prefab.
Once you've done this in a handler script attached to an empty gameobject in your canvas make a list of gameobjects:
List<GameObject> chocolatePieces = new List<GameObject>();
You'll want to at the top of your handler script define GameObject chocolatePiece and attach in your inspector the prefab we defined earlier. Then in Start(), loop the size of how many chocolate pieces you want, for your example lets use 4. Instantiate 4 of the prefabs you defined earlier as gameobjects and for each define their properties just like this:
Example variables:
int x = -200;
int y = 200;
int amountToMoveInX = 200;
int amountToMoveInY = 100;
Example instantiation code:
GameObject newPiece = (GameObject)Instantiate(chocolatePiece);
chocolatePieces.Add(newPiece);
newPiece.GetComponent<ChocolatePiece>().ID = i;
newPiece.transform.SetParent(gameObject.transform, false);
newPiece.name = ("ChocolatePiece" + i);
newPiece.GetComponent<RectTransform>().localPosition = new Vector3(x, y, 0);
From this point add to your positions (x by amountToMoveInX and y by amountToMoveInY) for the next loop count;
(For the transform.position, each count of your loop add an amount on to a default x and default y value (the position of your first piece most likely))
Now because you have all your gameobjects in a list with their properties properly set you can then access these gameobjects through your handler script.
I am using two canvases in my project, synchronizing moving objects in the two containers. The challenge is after moving one object, I can't drag any object in the second container.
I am using:
blueLine2.on('dragmove', function () {
circle2.x(blueLine2.x() + blueLine2.points()[0]);
blueLine1.setPosition({ x: blueLine2.x() * 2, y: blueLine2.y() * 2 });
circle1.x(blueLine1.x() + blueLine1.points()[0]);
guides2.draw();
guides1.draw();
});
Here is the complete code: http://jsfiddle.net/user373721/6f1e0c1p/
Would appreciate your suggestions.
For performance reasons KineticJS is not drawing hit canvas while dragging. So you have to update hit canvas after dragend:
greenLine1.on('dragend', function() {
guides2.draw();
});
http://jsfiddle.net/6f1e0c1p/1/
How to know the distance of the Drag, unused PositionUP or onInputUp to differentiate a drag from a long click?
http://i.stack.imgur.com/FvVsN.pnghttp://www.html5gamedevs.com/uploads/monthly_07_2014/post-9642-0-48696600-1405440289.png
it is a some code:
var fnd = game.add.group();
var o = fnd.create(game.world.randomX, game.world.randomY, 'fon');
o.events.onDragStart.add(this.DragActivo, this);
DragActive = function (image) {
//When something has been moved is drag but when something has been pressed for long time is clicked
};
You can use the property sprite.input.dragDistanceThreshold = 3; in order to start dragging only if the pointer moves a minimum amount of pixels when after onInputDown.
Here's the doc
I solved my problem that you have to do something like this.
I used the function mouseup and inside this one I placed the mousemove to recognize when the mouse moves it is a drag, if it does not do it is a very long click
because this framework does not have