001package conexp.fx.gui.graph; 002 003/* 004 * #%L 005 * Concept Explorer FX 006 * %% 007 * Copyright (C) 2010 - 2019 Francesco Kriegel 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025import java.util.Set; 026 027import com.google.common.collect.HashMultimap; 028import com.google.common.collect.Multimap; 029 030import conexp.fx.core.context.Concept; 031import conexp.fx.core.context.ConceptLattice; 032import javafx.event.EventHandler; 033import javafx.scene.Scene; 034import javafx.scene.input.MouseEvent; 035import javafx.scene.layout.Pane; 036import javafx.scene.layout.StackPane; 037import javafx.scene.paint.Color; 038import javafx.scene.shape.Shape; 039import javafx.stage.Stage; 040 041public class CircularGraph<G, M> { 042 043 private final Stage primaryStage; 044 045 public CircularGraph(final ConceptLattice<G, M> lattice) { 046 super(); 047 this.primaryStage = new Stage(); 048 final Pane rootPane = new StackPane(); 049 this.primaryStage.setScene(new Scene(rootPane, 1280, 800)); 050 final Multimap<Concept<G, M>, Area> layers = computeLayers(lattice, 360d, 36d); 051 final Multimap<Concept<G, M>, SuperNode> nodes = HashMultimap.<Concept<G, M>, SuperNode> create(); 052 for (Concept<G, M> c : layers.keySet()) 053 for (Area a : layers.get(c)) { 054 final SuperNode n = new SuperNode(a.y, a.y + a.h, a.x, a.w, fromHashCode(c)); 055 nodes.put(c, n); 056 rootPane.getChildren().add(n); 057 addListener(c, n, nodes); 058 } 059 } 060 061 public final void show() { 062 this.primaryStage.show(); 063 } 064 065 private void addListener(final Concept<G, M> c, final SuperNode n, final Multimap<Concept<G, M>, SuperNode> nodes) { 066 ((Shape) n.getChildren().get(1)).addEventHandler(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() { 067 068 @Override 069 public void handle(MouseEvent event) { 070 for (SuperNode node : nodes.get(c)) 071 ((Shape) node.getChildren().get(1)).setFill(Color.RED); 072 } 073 }); 074 ((Shape) n.getChildren().get(1)).addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() { 075 076 @Override 077 public void handle(MouseEvent event) { 078 for (SuperNode node : nodes.get(c)) 079 ((Shape) node.getChildren().get(1)).setFill(fromHashCode(c)); 080 } 081 }); 082 } 083 084 private Color fromHashCode(final Object o) { 085// int rnd = (int) (new Random().nextFloat() * 23f); 086 int h = o.hashCode();// * rnd; 087 int m = 192; 088 int r = (h * 7) % m; 089 int g = (h * 17) % m; 090 int b = (h * 37) % m; 091 if (r < 0) 092 r += m; 093 if (g < 0) 094 g += m; 095 if (b < 0) 096 b += m; 097 r += (256 - m); 098 g += (256 - m); 099 b += (256 - m); 100 return Color.rgb(r, g, b); 101 } 102 103 private class Area { 104 105 private final double x, y, w, h; 106 107 public Area(double x, double y, double w, double h) { 108 super(); 109 this.x = x; 110 this.y = y; 111 this.w = w; 112 this.h = h; 113 } 114 115 } 116 117 private Multimap<Concept<G, M>, Area> computeLayers( 118 final ConceptLattice<G, M> lattice, 119 final double width, 120 final double layerHeight) { 121 final Multimap<Concept<G, M>, Area> layers = HashMultimap.<Concept<G, M>, Area> create(); 122 final Concept<G, M> top = lattice.context.topConcept(); 123 final Area parent = new Area(0, 0, width, layerHeight); 124 layers.put(top, parent); 125 addNextLayer(lattice, layers, parent, lattice.col(top)); 126 return layers; 127 } 128 129 private void addNextLayer( 130 final ConceptLattice<G, M> lattice, 131 final Multimap<Concept<G, M>, Area> layers, 132 final Area parent, 133 final Set<Concept<G, M>> concepts) { 134 double l = parent.w / (double) concepts.size(); 135 double t = parent.x; 136 for (Concept<G, M> c : concepts) { 137 final Area a = new Area(t, parent.y + parent.h, l, parent.h); 138 layers.put(c, a); 139 addNextLayer(lattice, layers, a, lattice.col(c)); 140 t += l; 141 } 142 } 143}