package cl.cromer.estructuras; import javafx.animation.Animation; import javafx.animation.PauseTransition; import javafx.animation.SequentialTransition; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; import javafx.scene.shape.Polygon; import javafx.scene.shape.Rectangle; import javafx.scene.text.Text; import javafx.util.Duration; import java.util.ArrayList; import java.util.List; /** * Esta clase es para trabajar con graficos. * * @author Chris Cromer */ public class Grafico { /** * Duración de la animación. */ static final public int DURACION = 150; /** * Tipo de dibujo rectuangular. */ static final public int RECTANGULO = 0; /** * Tipo de dibujo circular. */ static final public int CIRCULO = 1; /** * Tipo de dibjuo texto */ static final public int TEXTO = 2; /** * La escena donde está cosas graficas. */ final private Scene scene; /** * Los elementos destacados. */ final private List destacados; /** * Graficar una escena. * * @param scene La scene a destacar. */ public Grafico(Scene scene) { this.scene = scene; destacados = new ArrayList<>(); } /** * Crear una flecha que apunta por abajo. * * @return StackPane: Devolver el stackpane que contiene la flecha. */ public static StackPane crearFlechaAbajo() { Polygon polygon = new Polygon(); polygon.getPoints().addAll( 0.0, 0.0, 10.0, 0.0, 5.0, 10.0 ); StackPane stackPane = new StackPane(); stackPane.getChildren().addAll(polygon); return stackPane; } /** * Crear una linea horizontal para conecatar nodos de arboles. * * @return Pane: Devolver el pane que contiene la linea. */ public static Pane crearEsquinaDerecha() { Line right = new Line(); right.setStartY(21); right.setEndY(21); right.setStartX(20); right.setEndX(40); Line up = new Line(); up.setStartY(21); up.setEndY(40); up.setStartX(20); up.setEndX(20); Pane stackPane = new Pane(); stackPane.getChildren().addAll(right, up); return stackPane; } /** * Crear una linea para conectar arboles. * * @return Pane: Devolver el pane que contiene las lienas. */ public static Pane crearEsquinaIzquerda() { Line left = new Line(); left.setStartY(21); left.setEndY(21); left.setStartX(0); left.setEndX(20); Line up = new Line(); up.setStartY(21); up.setEndY(40); up.setStartX(20); up.setEndX(20); Pane stackPane = new Pane(); stackPane.getChildren().addAll(left, up); return stackPane; } /** * Crear una linea para conectar arboles. * * @return StackPane: Devolver el pane que contiene las lienas. */ public static StackPane crearLineaHorizontal() { Line line = new Line(); line.setStrokeWidth(1.5); line.setStartY(20); line.setEndY(20); line.setStartX(0); line.setEndX(40); StackPane stackPane = new StackPane(); stackPane.getChildren().addAll(line); return stackPane; } /** * Crear una flecha que apunta por arriba. * * @return StackPane: Devolver el stackpane que contiene la flecha. */ public static StackPane crearFlechaArriba() { Polygon polygon = new Polygon(); polygon.getPoints().addAll( 5.0, 0.0, 0.0, 10.0, 10.0, 10.0 ); StackPane stackPane = new StackPane(); stackPane.getChildren().addAll(polygon); return stackPane; } /** * Crear una linea vertical. * * @return StackPane: Devolver el stackpane que contiene la linea vertical. */ public static StackPane crearLineaVertical() { Line line = new Line(); line.setStartX(20); line.setEndX(20); line.setStartY(0); line.setEndY(20); StackPane stackPane = new StackPane(); stackPane.getChildren().addAll(line); return stackPane; } /** * Crear la linea circular con flecha. * * @param cajas int: La cantidad de cajas que están. * * @return StackPane: Devolver el stackpane que contiene la linea horizontal. */ public static Pane crearLineaCircular(int cajas) { int height = (cajas - 1) * (40 + 20 + 10); height = height + 20 + 10; Line top = new Line(); top.setStartY(20); top.setEndY(20); top.setStartX(0); top.setEndX(20); Polygon flechaDerecha = new Polygon(); flechaDerecha.getPoints().addAll( 10.0, 15.0, 20.0, 20.0, 10.0, 25.0 ); Line vertical = new Line(); vertical.setStartY(20); vertical.setEndY(height); Line bottom = new Line(); bottom.setStartY(height); bottom.setEndY(height); bottom.setStartX(0); bottom.setEndX(20); Pane stackPane = new Pane(); stackPane.getChildren().addAll(top, flechaDerecha, vertical, bottom); return stackPane; } /** * Crear un rectangulo. * * @param colores Colores: Los colores para dar color al rectangulo. * @param label String: El texto por el ID de fxml. * * @return StackPane: Devolver el stackpane que contiene el rectangulo y texto. */ public static StackPane crearCaja(Colores colores, String label) { Rectangle rectangle = new Rectangle(); rectangle.setHeight(40); rectangle.setWidth(40); rectangle.setFill(colores.getFondo()); rectangle.setStroke(colores.getBorder()); rectangle.setId("caja_" + label); Text text = new Text(); text.setId("texto_" + label); text.setStroke(colores.getTexto()); StackPane stackPane = new StackPane(); stackPane.getChildren().addAll(rectangle, text); return stackPane; } /** * Crear un rectangulo con texto adentro. * * @param colores Colores: Los colores para dar color al rectangulo. * @param label String: El texto por el ID de fxml. * @param texto String: El texto a colocar dentro el rectangulo. * * @return StackPane: Devolver el stackpane que contiene el rectangulo y texto. */ public static StackPane crearCaja(Colores colores, String label, String texto) { Rectangle rectangle = new Rectangle(); rectangle.setHeight(40); rectangle.setWidth(40); rectangle.setFill(colores.getFondo()); rectangle.setStroke(colores.getBorder()); rectangle.setId("caja_" + label); Text text = new Text(); text.setId("texto_" + label); text.setStroke(colores.getTexto()); text.setText(texto); StackPane stackPane = new StackPane(); stackPane.getChildren().addAll(rectangle, text); return stackPane; } public static StackPane crearCirculo(Colores colores, String label) { Circle circle = new Circle(); circle.setRadius(20); circle.setFill(colores.getFondo()); circle.setStroke(colores.getBorder()); circle.setId("circulo_" + label); Text text = new Text(); text.setId("texto_" + label); text.setStroke(colores.getTexto()); StackPane stackPane = new StackPane(); stackPane.getChildren().addAll(circle, text); return stackPane; } /** * Crear 3 rectangulos. * * @param colores Colores: Los colores para dar color a los rectangulos. * @param label String: El texto por el ID de fxml. * * @return StackPane: Devolver el stackpane que contiene los rectangulos y textos. */ public static StackPane crearHashCajas(Colores colores, String label) { Rectangle rectangle = new Rectangle(); rectangle.setHeight(40); rectangle.setWidth(40); rectangle.setFill(colores.getFondo()); rectangle.setStroke(colores.getBorder()); rectangle.setId("indice_caja_" + label); Text text = new Text(); text.setId("indice_texto_" + label); text.setStroke(colores.getTexto()); StackPane stackPane1 = new StackPane(); stackPane1.getChildren().addAll(rectangle, text); rectangle = new Rectangle(); rectangle.setHeight(40); rectangle.setWidth(120); rectangle.setFill(colores.getFondo()); rectangle.setStroke(colores.getBorder()); rectangle.setId("llave_caja_" + label); text = new Text(); text.setId("llave_texto_" + label); text.setStroke(colores.getTexto()); StackPane stackPane2 = new StackPane(); stackPane2.getChildren().addAll(rectangle, text); rectangle = new Rectangle(); rectangle.setHeight(40); rectangle.setWidth(40); rectangle.setFill(colores.getFondo()); rectangle.setStroke(colores.getBorder()); rectangle.setId("valor_caja_" + label); text = new Text(); text.setId("valor_texto_" + label); text.setStroke(colores.getTexto()); StackPane stackPane3 = new StackPane(); stackPane3.getChildren().addAll(rectangle, text); HBox hBox = new HBox(); hBox.getChildren().addAll(stackPane1, stackPane2, stackPane3); hBox.setAlignment(Pos.TOP_CENTER); StackPane stackPane = new StackPane(); stackPane.getChildren().addAll(hBox); return stackPane; } /** * Destacar un elemento * * @param id int: El indice a destacar. * @param tipo int: El tipo de objeto a destacar, {@value #RECTANGULO}, {@value #CIRCULO} o {@value #TEXTO} */ public void destacar(String id, int tipo) { if (tipo != RECTANGULO && tipo != CIRCULO && tipo != TEXTO) { return; } Colores colores = new Colores(); Rectangle rectangle = null; Circle circle = null; Text text = null; if (tipo == RECTANGULO) { rectangle = (Rectangle) scene.lookup(id); } else if (tipo == CIRCULO) { circle = (Circle) scene.lookup(id); } else { text = (Text) scene.lookup(id); } PauseTransition changeColor[] = new PauseTransition[Colores.MAX_COLORS]; for (int i = 0; i < Colores.MAX_COLORS; i++) { if (tipo == RECTANGULO) { changeColor[i] = createPauseTransition(rectangle, colores.getFondo()); } else if (tipo == CIRCULO) { changeColor[i] = createPauseTransition(circle, colores.getFondo()); } else { changeColor[i] = createPauseTransition(text, colores.getTexto()); } colores.siguinteColor(); } if (tipo == RECTANGULO) { destacados.add(new Destacados(tipo, id, (Color) rectangle.getFill(), new SequentialTransition(changeColor))); } else if (tipo == CIRCULO) { destacados.add(new Destacados(tipo, id, (Color) circle.getFill(), new SequentialTransition(changeColor))); } else { destacados.add(new Destacados(tipo, id, (Color) text.getStroke(), new SequentialTransition(changeColor))); } destacados.get(destacados.size() - 1).getSequentialTransition().setCycleCount(Animation.INDEFINITE); destacados.get(destacados.size() - 1).getSequentialTransition().play(); } /** * Crear un animacion de transicion usando colores que cambian. * * @param rectangle Rectangle: El objeto que desea animar. * @param colorBackground Color: Color del fondo de destacar. * * @return PauseTransition: La transition creado con los elementos y colores. */ private static PauseTransition createPauseTransition(Rectangle rectangle, Color colorBackground) { PauseTransition changeColor = new PauseTransition(new Duration(DURACION)); changeColor.setOnFinished(actionEvent -> rectangle.setFill(colorBackground)); return changeColor; } /** * Crear un animacion de transicion usando colores que cambian. * * @param circle Circle: El objeto que desea animar. * @param colorBackground Color: Color del fondo de destacar. * * @return PauseTransition: La transition creado con los elementos y colores. */ private static PauseTransition createPauseTransition(Circle circle, Color colorBackground) { PauseTransition changeColor = new PauseTransition(new Duration(DURACION)); changeColor.setOnFinished(actionEvent -> circle.setFill(colorBackground)); return changeColor; } /** * Crear un animacion de transicion usando colores que cambian. * * @param text Text: El texto que desea animar. * @param colorText Color: Color del texto. * * @return PauseTransition: La transition creado con los elementos y colores. */ private static PauseTransition createPauseTransition(Text text, Color colorText) { PauseTransition changeColor = new PauseTransition(new Duration(DURACION)); changeColor.setOnFinished(actionEvent -> text.setStroke(colorText)); return changeColor; } /** * Remover todos los elementos destacados. */ public void removerDestacar() { if (destacados.size() != 0) { int size = destacados.size(); for (int i = 0; i < size; i++) { destacados.get(0).getSequentialTransition().stop(); if (destacados.get(0).getTipo() == RECTANGULO) { Rectangle rectangle = (Rectangle) scene.lookup(destacados.get(0).getId()); rectangle.setFill(destacados.get(0).getColor()); } else if (destacados.get(0).getTipo() == CIRCULO) { Circle circle = (Circle) scene.lookup(destacados.get(0).getId()); circle.setFill(destacados.get(0).getColor()); } else { Text text = (Text) scene.lookup(destacados.get(0).getId()); text.setStroke(destacados.get(0).getColor()); } destacados.remove(0); } } } /** * Clase de elemento destacado. * * @author Chris Cromer */ final static private class Destacados { /** * El tipo de objeto que está destacado. */ final private int tipo; /** * El id del elemento destacado. */ final private String id; /** * El color anterior del elemento destacado. */ final private Color color; /** * La animación del elemento destacado. */ final private SequentialTransition sequentialTransition; /** * Inicilizar. * @param tipo int: El tipo de elemento destacado, {@value #RECTANGULO}, {@value #CIRCULO} o {@value #TEXTO}. * @param id String: El id para identificar el elemento. * @param color Color: El color anterior para cambiarlo cuando {@link #removerDestacar()} es usado. * @param sequentialTransition SequentialTransition: La animación a usar. */ public Destacados(int tipo, String id, Color color, SequentialTransition sequentialTransition) { this.tipo = tipo; this.id = id; this.color = color; this.sequentialTransition = sequentialTransition; } /** * Devolver el tipo de elemento destacado. * @return int: El tipo destacado. */ public int getTipo() { return tipo; } /** * Devolver el ID de elemento destacado. * @return String: El ID destacado. */ public String getId() { return id; } /** * Devolver el color anterior antes que fue destacado. * * @return Color: El color anterior. */ public Color getColor() { return color; } /** * Devolver la animación que es en uso con el elemento. * @return SequentialTransition: La animación. */ public SequentialTransition getSequentialTransition() { return sequentialTransition; } } }