blob: 8da25c7be60e567f2a4912db9f33158235853fd9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.kie.lienzo.client;
import com.ait.lienzo.client.core.animation.IAnimation;
import com.ait.lienzo.client.core.animation.IAnimationCallback;
import com.ait.lienzo.client.core.animation.IAnimationHandle;
import com.ait.lienzo.client.core.animation.TimedAnimation;
import com.ait.lienzo.client.core.shape.Circle;
import com.ait.lienzo.client.core.shape.Group;
import com.ait.lienzo.client.core.shape.Rectangle;
import com.ait.lienzo.client.core.shape.Slice;
import com.ait.lienzo.client.core.shape.Text;
import com.ait.lienzo.client.core.types.Point2D;
import com.ait.lienzo.client.core.types.Point2DArray;
import com.ait.lienzo.client.core.types.Shadow;
import com.ait.lienzo.client.core.types.Transform;
import com.ait.lienzo.client.widget.panel.LienzoPanel;
import com.ait.lienzo.shared.core.types.ColorName;
import elemental2.dom.HTMLDivElement;
public class Transform3PointsExample extends BaseExample implements Example {
private static final int WIDTH = 200;
private static final int DX = 20;
private static final int DY = 20;
private static final String TEXT_FONT = "oblique normal bold";
private static final int TEXT_SIZE = 16;
private SliceGroup node;
private DragPoint[] fromPoints;
private DragPoint[] toPoints;
private Button animateButton;
private Text[] animateText = new Text[3];
private Button resetButton;
private Text[] resetText = new Text[3];
private Transform originalTransform;
private Transform fromTransform;
private Transform toTransform;
private double[] transform = new double[6];
public Transform3PointsExample(final String title) {
super(title);
}
@Override
public void init(final LienzoPanel panel, final HTMLDivElement topDiv) {
super.init(panel, topDiv);
node = new SliceGroup(WIDTH, "red");
// Use a Transform to position the node, rather than using X,Y attributes,
// because we're going to animate the transform (below)
originalTransform = new Transform().translate(DX, DY);
//originalTransform.
node.setTransform(originalTransform);
layer.add(node);
fromPoints = new DragPoint[3];
fromPoints[0] = new DragPoint("1", "blue", DX, DY + WIDTH);
layer.add(fromPoints[0]);
fromPoints[1] = new DragPoint("2", "blue", DX, DY);
layer.add(fromPoints[1]);
fromPoints[2] = new DragPoint("3", "blue", DX + WIDTH, DY);
layer.add(fromPoints[2]);
toPoints = new DragPoint[3];
toPoints[0] = new DragPoint("1'", "red", 525, 325);
layer.add(toPoints[0]);
toPoints[1] = new DragPoint("2'", "red", 600, 350);
layer.add(toPoints[1]);
toPoints[2] = new DragPoint("3'", "red", 560, 250);
layer.add(toPoints[2]);
animateButton = new Button("Animate");
animateButton.setX(200).setY(430);
animateButton.addNodeMouseClickHandler((e) -> animate());
animateButton.addNodeTouchStartHandler((e) -> animate());
layer.add(animateButton);
resetButton = new Button("Reset");
resetButton.setX(400).setY(430).setVisible(false);
resetButton.addNodeMouseClickHandler((e) -> reset());
resetButton.addNodeTouchStartHandler((e) -> reset());
layer.add(resetButton);
animateText[0] = new Text("Drag the red target points to the desired location and click 'Animate'.", TEXT_FONT, TEXT_SIZE);
animateText[0].setX(10).setY(500).setFillColor("black");
layer.add(animateText[0]);
animateText[1] = new Text("It will calculate the Transform that projects the blue (source) points onto the red (target) points,", TEXT_FONT, TEXT_SIZE);
animateText[1].setX(10).setY(525).setFillColor("black");
layer.add(animateText[1]);
animateText[2] = new Text("and animate the transition.", TEXT_FONT, TEXT_SIZE);
animateText[2].setX(10).setY(550).setFillColor("black");
layer.add(animateText[2]);
resetText[0] = new Text("Click 'Reset' to restart the demo.", TEXT_FONT, TEXT_SIZE);
resetText[0].setX(10).setY(500).setFillColor("black").setVisible(false);
layer.add(resetText[0]);
resetText[1] = new Text("Note that the (blue) source points don't necessarily need to be on the shape.", TEXT_FONT, TEXT_SIZE);
resetText[1].setX(10).setY(525).setFillColor("black").setVisible(false);
layer.add(resetText[1]);
resetText[2] = new Text("Try moving them before animating the next time.", TEXT_FONT, TEXT_SIZE);
resetText[2].setX(10).setY(550).setFillColor("black").setVisible(false);
layer.add(resetText[2]);
}
@Override
public void run() {
}
public void animate() {
Point2DArray src = new Point2DArray();
for (int i = 0; i < fromPoints.length; i++) {
src.push(new Point2D(fromPoints[i].getX(), fromPoints[i].getY()));
}
Point2DArray target = new Point2DArray();
for (int i = 0; i < toPoints.length; i++) {
target.push(new Point2D(toPoints[i].getX(), toPoints[i].getY()));
}
// Calculate the Transform to go from the 3 source points to the 3 target points
fromTransform = node.getAbsoluteTransform();
if (fromTransform == null) {
fromTransform = new Transform();
}
// Here's the magic. We'll do the math for you!
toTransform = Transform.create3PointTransform(src, target).multiply(fromTransform);
TimedAnimation handle = new TimedAnimation(5000, new IAnimationCallback() {
@Override
public void onStart(IAnimation animation, IAnimationHandle handle) {
// Hide the Animate button and associated text
animateButton.setVisible(false);
for (int i = 0; i < animateText.length; i++) {
animateText[i].setVisible(false);
}
repaint();
}
@Override
public void onFrame(IAnimation animation, IAnimationHandle handle) {
// Calculate the transform between the fromTransform and the toTransform.
// If percent=0, transform will result in the fromTransform.
// If percent=1, transform will result in the toTransform.
// Any other percent value will fall somewhere in between (in a linear fashion.)
for (int i = 0; i < 6; i++) // a Transform matrix has 6 values
{
double d = fromTransform.get(i);
transform[i] = d + animation.getPercent() * (toTransform.get(i) - d);
}
// Set the Transform on the node
node.setTransform(Transform.makeFromArray(transform));
repaint();
}
@Override
public void onClose(IAnimation animation, IAnimationHandle handle) {
// Show the Reset button and associated text
resetButton.setVisible(true);
for (int i = 0; i < resetText.length; i++) {
resetText[i].setVisible(true);
}
repaint();
}
});
handle.setNode(node);
handle.run(); // start the animation
}
private void repaint() {
layer.getScene().draw();
}
protected void reset() {
animateButton.setVisible(true);
for (int i = 0; i < animateText.length; i++) {
animateText[i].setVisible(true);
}
resetButton.setVisible(false);
for (int i = 0; i < resetText.length; i++) {
resetText[i].setVisible(false);
}
// Put the node back in its original location
node.setTransform(originalTransform);
// Put the blue source points back
fromPoints[0].setX(DX).setY(DY + WIDTH);
fromPoints[1].setX(DX).setY(DY);
fromPoints[2].setX(DX + WIDTH).setY(DY);
repaint();
}
// A SliceGroup is a Group with a Rectangle and some Slices and Text inside the Rectangle.
// One Slice is scaled and one is rotated.
public static class SliceGroup extends Group {
private double width;
public SliceGroup(double w, String color) {
width = w;
add(new Rectangle(w, w).setStrokeColor(color));
double r = w / 4;
Slice s = new Slice(r, 0, Math.PI / 2, true);
s.setX(r).setY(r);
s.setFillColor(color);
s.setDraggable(true);
add(s);
Text t = new Text("Slices", "oblique normal bold", w / 15);
t.setX(r * 0.6).setY(r * 0.8);
t.setFillColor(ColorName.YELLOW);
add(t);
s = new Slice(r, 0.75 * Math.PI, 3 * Math.PI / 2, true);
s.setX(3 * r).setY(r);
s.setScale(0.5);
s.setFillColor(color);
s.setDraggable(true);
add(s);
s = new Slice(r, 0, Math.PI);
s.setX(r).setY(3 * r);
s.setRotation(Math.PI / 4);
s.setFillColor(color);
s.setDraggable(true);
add(s);
}
public SliceGroup addSliceGroup(String color) {
SliceGroup s = new SliceGroup(width, color);
s.setRotation(-Math.PI / 2);
s.setScale(0.5);
double r = width / 4;
s.setX(r * 2).setY(r * 4);
add(s);
return s;
}
}
public static class DragPoint extends Group {
public DragPoint(String label, String color, int x, int y) {
Circle c = new Circle(10);
c.setFillColor(color);
c.setStrokeColor(ColorName.BLACK);
c.setStrokeWidth(1);
add(c);
Text text = new Text(label);
text.setFillColor(ColorName.WHITE);
text.setFontSize(8);
text.setX(-4);
text.setY(3);
add(text);
setX(x);
setY(y);
setDraggable(true);
}
}
public class Button extends Group {
public Button(String label) {
Rectangle r = new Rectangle(100, 30, 5);
r.setFillColor("green");
r.setShadow(new Shadow(ColorName.DARKGREEN.getValue(), 6, 6, 6));
add(r);
Text text = new Text(label);
text.setFillColor("white");
text.setFontSize(16);
text.setX(15);
text.setY(20);
text.setListening(false);
add(text);
}
}
}