Animate a SVG Element with Dart - animation

I'd like to animate a SVG Element using Dart. That is slowly moving a RectElement of the "dart:svg" package from one y-coordinate to another. Unfortunately I couldn't find an example. I also tried to use the animation package found here here but it seems not to work with SVG elements.

You can achieve this by using animation frames and updating the y attribute (keeping in mind that it is a string):
import 'dart:html';
import 'dart:svg';
import 'dart:async';
RectElement rect;
int pos = 0;
int dest = 300;
void main() {
// Get a reference to the element
rect = query("#rect");
// Start the animation
window.animationFrame.then(animate);
}
void animate(num delta) {
// Keep moving the element down until we reach the destination
if(pos < dest) {
pos += 2;
rect.attributes['y'] = pos.toString();
// Continue the animation
window.animationFrame.then(animate);
}
}
Edit: Switched from timers to animation frames as per Greg Lowe's suggestion

I realize this question is old, however, some days ago I wrote an example about it in my blog.
This is using the pub package tweenengine
The steps are basically:
Creating an accessor for whatever svg element you are trying to animate
create a TweenManager
on your window.animation.then() call the tweenmanager's update.
I did create a gist for it as well.

Related

How to keep image original in QgraphicsView in QT

I have load an image in QGraphicsView, but consider of the size of QGraphicsView scene, I need to scale the image first, then add the scaled image to scene.
e.g. The image original size is 1536*1024, the QGraphicsView size is 500*400, firstly I scale the image like this:
image2D = image2D.scaled( h * P , h, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
myScene->setSceneRect((h * P-w)/2, 0, h * P , h);
pixmapItem = new QGraphicsPixmapItem(image2D);
myScene->addItem(pixmapItem);
myView->setScene(myScene);
And now a problem comes to me, when wheelEvent happends and the QGraphicsView zoom in, the scaled image becomes indistinct while I want it to keep as clear as the original one.
I find a way that I can hold an original copy of image, then when wheelEvent happend just scale the original copy and put it to scene.
But I don't know how to write this code, thanks for help~
or are there any simple methods?
class interactiveView : public QGraphicsView
{
protected:
void wheelEvent(QWheelEvent *event) override;
}
void interactiveView::wheelEvent(QWheelEvent *event)
{
int scrollAmount = event->delta();
xPos = event->pos().x();
yPos = event->pos().y();
scrollAmount > 0 ? zoomIn() : zoomOut();
}
Update:
I find a simple way like this:
just use QGraphicsView::fitInView() to make sure that the image scale is equal to QGraphicsView, and do not need to scale image first.
Therefore the image won't be indistinct when zoom in, and I only need to recall the QGraphicsView::fitInView() to reset to original view instead of using QGraphicsView::resetMatrix()
void myImageWindow::loadImag(int w, int h)
{
pixmapItem->setPixmap(image2D);
//if the scale of image changed
if(image2D.height() != imgHeight_pre){
myView->fitInView(pixmapItem, Qt::KeepAspectRatioByExpanding);
imgHeight_pre = image2D.height();
}
//if the scene of QGraphicsView changed
if(h != sceneHeight_pre){
myView->fitInView(pixmapItem, Qt::KeepAspectRatioByExpanding);
sceneHeight_pre = h;
}
}
void myImageWindow::on_rstImgBtn_clicked()
{
myView->fitInView(pixmapItem, Qt::KeepAspectRatioByExpanding);
}
Scaled image:
becomes indistinct when zoom in:
You can use this method resetMatrix() to reset image
For example:
graphicsView->scale(2, 2);
graphicsView->resetMatrix();
graphicsView->scale(1, 1);

How to resize child QLabel (having a QPixmap) with QHBLayout keeping aspect ratio?

I am dynamically creating a QLabel named label (that has a QPixmap) inside a QHBLayout named layout inside a parent QWidget named by this such that the QLabel image resizes with parent this but maintains the original image aspect ratio.
What I am doing now is the following:
QHBoxLayout* layout = new QHBoxLayout(this);
label = new QLabel(str, this); /* This Label is my concern */
label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
layout->addWidget(label);
layout->setAlignment(Qt::AlignCenter);
this->setLayout(layout);
layout->setContentsMargins(0,0,0,0);
layout->setSpacing(0);
label->setScaledContents(true);
label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
After searching online and as suggested in the accepted answer in Qt layouts - Keep widget aspect ratio while resizing, I even tried creating my own MyLabel class and defining sizeHint() and resizeEvent(QResizeEvent* event) as follows:
QSize MyLabel::sizeHint() const
{
QSize s = size();
lastHeight = s.height();
lastWidth = s.width();
QSize qs = QLabel::sizeHint();
float ratio = std::min(((float)qs.width())/lastWidth, ((float)qs.height())/lastHeight);
s.setWidth(lastWidth*ratio);
s.setHeight(lastHeight*ratio);
return s;
}
void MyLabel::resizeEvent(QResizeEvent* event)
{
QLabel::resizeEvent(event);
if(lastHeight!=height())
{
updateGeometry();
}
}
But the label image still resizes without maintaining aspect ratio.
What am I missing here?
Any help will be highly appreciated.
Thanks in advance.
Try using the subclass of QLabel listed here:
https://stackoverflow.com/a/22618496/999943
Hope that helps.
Try to resize your image instead of QLabel. E.g. by hangling parent widget's resizeEvent and doing something like:
const QPixmap* pixmap = label->pixmap();
if (pixmap->width() >= newGeometry.width())
{
QPixmap scaledPixmap = pixmap->scaledToWidth(newWidth, Qt::SmoothTransformation);
label->setPixmap(scaledPixmap);
}

Add Image dynamically in runtime - Unity 5

In my unity based Android game I wish to add the image dynamically based on the number of questions in each level. The image is shown for reference. Each correct answer will be marked in green and the wrong one in red. I am new to unity and trying hard to find steps to achieve this.
Any help with an example for this requirement will be a great help.
I once wrote a script for dynamically creating buttons based on each level. What I did was creating the first button on the scene and adding the other buttons based on the first one. Below is the shell of my code:
// tutorialButton and levelButtons are public variables which can be set from Inspector
RectTransform rect = tutorialButton.GetComponent<RectTransform> ();
for (int i = 1; i < levelSize; i++) {
// Instantiate the button dynamically
GameObject newButton = GameObject.Instantiate (tutorialButton);
// Set the parent of the new button (In my case, the parent of tutorialButton)
newButton.transform.SetParent (levelButtons.transform);
//Set the scale to be the same as the tutorialButton
newButton.transform.localScale = tutorialButton.transform.localScale;
//Set the position to the right of the tutorialButton
Vector3 position = tutorialButton.transform.localPosition;
position.x += rect.rect.width*i;
newButton.transform.localPosition = position;
}
I am not exactly sure if this is the right approach as it may or may not give unexpected results depending on different screen sizes and your canvas, but hopefully it gives you an idea about dynamically creating objects.
I'm not sure if this helps, but if you have all the images in the scene under a canvas, with this you just need to drag the canvas on the script and use
//level-1 is to keep the array notation
FindObjectOfType<NameOfScript>.ChangeColor(level-1,Color.green);
or you can do also
//level-1 is to keep the array notation
FindObjectOfType<NameOfScript>.RevertColor(level - 1);
This is the script:
//Keep it private but you still see it in inspector
//#Encapsulation :)
[SerializeField]
private Canvas _canvas;
private Image[] _images;
//keep the original colors in case you want to change back
private Color[] _origColors;
void Start () {
_images = GetComponentsInChildren<Image>();
_origColors = new Color[_images.Length];
for (int i = 0; i < _images.Length; i++)
{
_origColors[i] = _images[i].color;
}
}
//Reverts the color of the image back to the original
public void RevertToOriginal(int imageIndex)
{
_images[imageIndex].color = _origColors[imageIndex];
}
//Change to color to the coresponding index, starts from 0
public void ChangeColor(int imageIndex, Color color)
{
_images[imageIndex].color = color;
}
P.S If you want it visible only at the end you can make a method where you enable = (true or false) for the canvas. So you keep it false till the end of the level and you make it true when you want to show, while after every answer you call the ChangeColor depending on the result.
To make it easier you can use:
NameOfScript variableName = FindObjectOfType<NameOfScript>();
and after that you just call
variableName.ChangeColor(level - 1, Color.green);
Also it does not matter where you put the script. I would make some kind of manager(empty GameObject) in the scene and put it there.

Networking rotation sync

My Unity version is 5.2.3f1, I m trying to sync the rotation of a child gameobject, in local works perfectly fine but it doesnt show up in other clients. I tried everything I could find and nothing.
The reason of this is to rotate a FPS body, so, I m trying to rotate Spine2 (Rotate the camera is not my best solution). I m using a Mixamo character to test, in the end I will have Mixamo auto-rigged charscters so everything I make here will be compatible.
I tried to use the Network Transform Rigidbody 3D and it only sync the character itself, not Spine2, I have tried Network Transform Child, and an official skeleton sync.
In the script part, I have tried a lot of things, the most promising one was this:
[SyncVar]
private Quaternion syncPlayerRotation;
[SerializeField]
private Transform playerTransform;
[SerializeField]
private float lerpRate = 15f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void LateUpdate () {
TransmitRotations();
LerpRotations();
}
void LerpRotations()
{
if (!isLocalPlayer)
playerTransform.localRotation = Quaternion.Lerp(playerTransform.localRotation, syncPlayerRotation, Time.deltaTime * lerpRate);
}
[Command]
void CmdProvideRotationsToServer(Quaternion playerRot)
{
syncPlayerRotation = playerRot;
}
[Client]
void TransmitRotations()
{
if (isLocalPlayer)
{
CmdProvideRotationsToServer(playerTransform.localRotation);
}
}
Its from UNET tutorial series on youtube, Gamer To Game Developer user.
I attached it to Spine2 and still dont work, but when I attached it to the main character, it worked.
Also tried this:
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
Vector3 syncPosition = Vector3.zero;
if (stream.isWriting)
{
syncPosition = Spine.GetComponent<Rigidbody>().position;
stream.Serialize(ref syncPosition);
}
else
{
stream.Serialize(ref syncPosition);
Spine.GetComponent<Rigidbody>().position = syncPosition;
}
}
But I think it was for an older version of Unity.
To make the rotations I m using A Free Simple Smooth Mouselook
I edited it, this lines:
if (Input.GetMouseButton(1))
{
var xRotation = Quaternion.AngleAxis(-_mouseAbsolute.y, targetOrientation * Vector3.forward);
transform.localRotation = xRotation;
}
else
{
var xRotation = Quaternion.AngleAxis(-_mouseAbsolute.y, targetOrientation * Vector3.right);
transform.localRotation = xRotation;
}
Basicly, I changed Vector3.right to Vector3.forward and converted the Vector3.right only if the right mouse button is not pressed. The script is attached to Spine2 and its activated on the start if(isLocalPlayer) by script.
There's a pic of the current hierarchy:
(some cameras are there only to test, the main camera is FirstPersonCamera, extracted from the standard assets)
I noticed that if I debug log the Spine2 rotation, it only gives me values from 0 to 1.

Showing images of an Actor changing in time as Animating

I am trying to animate 4 images of an actor but what i am seeing is only one image and no other change.
function init()
{
i=0;
while(i<ActStandX.length) //ActStandX holds the x locations of actor in a image spritesheet
{
for(var currentFrame=0;currentFrame<10;currentFrame++)
{
ctxBg.clearRect(0,0,800,600); //ctxBg is 2d context of canvas
ctxBg.drawImage(img,ActStandX[i],10,actWidth,actHeight,200,300,60,110);
}
i++;
}
requestAnimFrame(init);
}
i have tried this code so far but no success.
Try this:
var i = 0;
function init()
{
ctxBg.clearRect(0,0,800,600);
ctxBg.drawImage(img,ActStandX[i++],10,actWidth,actHeight,200,300,60,110);
if (i == ActStandX.length) i = 0; // loop the animation
requestAnimFrame(init);
}
Note that it will change frames every time it paints, so it may be faster than you actually want. It isn't hard to limit the incrementation of i based on the time passed, I'm sure you can figure it out. :)

Resources