summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/visualization/gui/detail
diff options
context:
space:
mode:
authorAndrej Shadura <andrewsh@debian.org>2019-03-09 22:30:28 +0000
committerAndrej Shadura <andrewsh@debian.org>2019-03-09 22:30:28 +0000
commitcde76aeb42240f7270bc6605c606ae07d2dc5a7d (patch)
treec3ebf1d7745224f524da31dbabc5d76b9ea75916 /src/de/lmu/ifi/dbs/elki/visualization/gui/detail
Import Upstream version 0.4.0~beta1
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/visualization/gui/detail')
-rw-r--r--src/de/lmu/ifi/dbs/elki/visualization/gui/detail/DetailView.java302
-rw-r--r--src/de/lmu/ifi/dbs/elki/visualization/gui/detail/package-info.java27
2 files changed, 329 insertions, 0 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/visualization/gui/detail/DetailView.java b/src/de/lmu/ifi/dbs/elki/visualization/gui/detail/DetailView.java
new file mode 100644
index 00000000..b5513c09
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/visualization/gui/detail/DetailView.java
@@ -0,0 +1,302 @@
+package de.lmu.ifi.dbs.elki.visualization.gui.detail;
+/*
+This file is part of ELKI:
+Environment for Developing KDD-Applications Supported by Index-Structures
+
+Copyright (C) 2011
+Ludwig-Maximilians-Universität München
+Lehr- und Forschungseinheit für Datenbanksysteme
+ELKI Development Team
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.batik.util.SVGConstants;
+import org.w3c.dom.Element;
+
+import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
+import de.lmu.ifi.dbs.elki.result.Result;
+import de.lmu.ifi.dbs.elki.result.ResultListener;
+import de.lmu.ifi.dbs.elki.visualization.batikutil.AttributeModifier;
+import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
+import de.lmu.ifi.dbs.elki.visualization.gui.overview.PlotItem;
+import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
+import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
+import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
+import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
+import de.lmu.ifi.dbs.elki.visualization.visualizers.VisualizationTask;
+import de.lmu.ifi.dbs.elki.visualization.visualizers.VisualizerContext;
+import de.lmu.ifi.dbs.elki.visualization.visualizers.VisualizerUtil;
+
+/**
+ * Manages a detail view.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.has VisualizerContext
+ * @apiviz.has Visualization
+ * @apiviz.has PlotItem
+ * @apiviz.uses VisualizationTask
+ */
+public class DetailView extends SVGPlot implements ResultListener {
+ /**
+ * Meta information on the visualizers contained.
+ */
+ PlotItem visi;
+
+ /**
+ * Ratio of this view.
+ */
+ double ratio = 1.0;
+
+ /**
+ * The visualizer context
+ */
+ VisualizerContext context;
+
+ /**
+ * Map from visualizers to layers
+ */
+ Map<VisualizationTask, Visualization> layermap = new HashMap<VisualizationTask, Visualization>();
+
+ /**
+ * The created width
+ */
+ private double width;
+
+ /**
+ * The created height
+ */
+ private double height;
+
+ /**
+ * Constructor.
+ *
+ * @param vis Visualizations to use
+ * @param ratio Plot ratio
+ */
+ public DetailView(VisualizerContext context, PlotItem vis, double ratio) {
+ super();
+ this.context = context;
+ this.visi = vis;
+ this.ratio = ratio;
+
+ Collections.sort(this.visi);
+
+ // TODO: only do this when there is an interactive visualizer?
+ setDisableInteractions(true);
+ addBackground(context);
+
+ redraw();
+ context.addResultListener(this);
+ }
+
+ /**
+ * Create a background node. Note: don't call this at arbitrary times - the
+ * background may cover already drawn parts of the image!
+ *
+ * @param context
+ */
+ private void addBackground(VisualizerContext context) {
+ // Make a background
+ CSSClass cls = new CSSClass(this, "background");
+ cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, context.getStyleLibrary().getBackgroundColor(StyleLibrary.PAGE));
+ Element bg = this.svgElement(SVGConstants.SVG_RECT_TAG);
+ SVGUtil.setAtt(bg, SVGConstants.SVG_X_ATTRIBUTE, "0");
+ SVGUtil.setAtt(bg, SVGConstants.SVG_Y_ATTRIBUTE, "0");
+ SVGUtil.setAtt(bg, SVGConstants.SVG_WIDTH_ATTRIBUTE, "100%");
+ SVGUtil.setAtt(bg, SVGConstants.SVG_HEIGHT_ATTRIBUTE, "100%");
+ addCSSClassOrLogError(cls);
+ SVGUtil.setCSSClass(bg, cls.getName());
+
+ // Note that we rely on this being called before any other drawing routines.
+ getDocument().getRootElement().appendChild(bg);
+ }
+
+ // TODO: protected?
+ protected void redraw() {
+ // TODO: Clear root children
+ // Warning: do not remove style and similar elements!
+ // while (getRoot().hasChildNodes()) {
+ // getRoot().removeChild(getRoot().getFirstChild());
+ // }
+ destroyVisualizations();
+
+ // Collections.sort(layers, new VisualizationInfoComparator());
+ width = getRatio();
+ height = 1.0;
+
+ ArrayList<Visualization> layers = new ArrayList<Visualization>(visi.size());
+ // TODO: center/arrange visualizations?
+ for(VisualizationTask task : visi) {
+ if(VisualizerUtil.isVisible(task)) {
+ try {
+ Visualization v = task.getFactory().makeVisualization(task.clone(this, context, visi.proj, width, height));
+ layers.add(v);
+ layermap.put(task, v);
+ }
+ catch(Exception e) {
+ if(Logging.getLogger(task.getFactory().getClass()).isDebugging()) {
+ LoggingUtil.exception("Visualization failed.", e);
+ }
+ else {
+ LoggingUtil.warning("Visualizer " + task.getFactory().getClass().getName() + " failed - enable debugging to see details.");
+ }
+ }
+ }
+ }
+ // Arrange
+ for(Visualization layer : layers) {
+ if(layer.getLayer() != null) {
+ this.getRoot().appendChild(layer.getLayer());
+ }
+ else {
+ LoggingUtil.warning("NULL layer seen.");
+ }
+ }
+
+ double ratio = width / height;
+ getRoot().setAttribute(SVGConstants.SVG_WIDTH_ATTRIBUTE, "20cm");
+ getRoot().setAttribute(SVGConstants.SVG_HEIGHT_ATTRIBUTE, (20 / ratio) + "cm");
+ getRoot().setAttribute(SVGConstants.SVG_VIEW_BOX_ATTRIBUTE, "0 0 " + width + " " + height);
+
+ updateStyleElement();
+ }
+
+ /**
+ * Cleanup function. To remove listeners.
+ */
+ public void destroy() {
+ context.removeResultListener(this);
+ destroyVisualizations();
+ }
+
+ private void destroyVisualizations() {
+ for(Entry<VisualizationTask, Visualization> v : layermap.entrySet()) {
+ v.getValue().destroy();
+ }
+ layermap.clear();
+ }
+
+ @Override
+ public void dispose() {
+ destroy();
+ super.dispose();
+ }
+
+ /**
+ * Get the plot ratio.
+ *
+ * @return the current ratio
+ */
+ public double getRatio() {
+ return ratio;
+ }
+
+ /**
+ * Set the plot ratio
+ *
+ * @param ratio the new ratio to set
+ */
+ public void setRatio(double ratio) {
+ // TODO: trigger refresh?
+ this.ratio = ratio;
+ }
+
+ /**
+ * Class used to insert a new visualization layer
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ protected class InsertVisualization implements Runnable {
+ /**
+ * The visualization to insert.
+ */
+ Visualization vis;
+
+ /**
+ * Visualization.
+ *
+ * @param vis
+ */
+ public InsertVisualization(Visualization vis) {
+ super();
+ this.vis = vis;
+ }
+
+ @Override
+ public void run() {
+ DetailView.this.getRoot().appendChild(vis.getLayer());
+ updateStyleElement();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @Override
+ public void resultAdded(Result child, Result parent) {
+ // Ignore. The PlotItem will need to change.
+ }
+
+ @Override
+ public void resultChanged(Result current) {
+ // Make sure we are affected:
+ if(!(current instanceof VisualizationTask)) {
+ return;
+ }
+ if(!visi.contains(current)) {
+ return;
+ }
+ // Get the layer
+ final VisualizationTask task = (VisualizationTask) current;
+ Visualization vis = layermap.get(task);
+ if(vis != null) {
+ // Ensure visibility is as expected
+ boolean isHidden = vis.getLayer().getAttribute(SVGConstants.CSS_VISIBILITY_PROPERTY) == SVGConstants.CSS_HIDDEN_VALUE;
+ if(VisualizerUtil.isVisible(task)) {
+ if(isHidden) {
+ this.scheduleUpdate(new AttributeModifier(vis.getLayer(), SVGConstants.CSS_VISIBILITY_PROPERTY, SVGConstants.CSS_VISIBLE_VALUE));
+ }
+ }
+ else {
+ if(!isHidden) {
+ this.scheduleUpdate(new AttributeModifier(vis.getLayer(), SVGConstants.CSS_VISIBILITY_PROPERTY, SVGConstants.CSS_HIDDEN_VALUE));
+ }
+ }
+ }
+ else {
+ // Only materialize when becoming visible
+ if(VisualizerUtil.isVisible(task)) {
+ // LoggingUtil.warning("Need to recreate a missing layer for " + v);
+ vis = task.getFactory().makeVisualization(task.clone(this, context, visi.proj, width, height));
+ layermap.put(task, vis);
+ this.scheduleUpdate(new InsertVisualization(vis));
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @Override
+ public void resultRemoved(Result child, Result parent) {
+ // Ignore. The PlotItem will need to change.
+ }
+} \ No newline at end of file
diff --git a/src/de/lmu/ifi/dbs/elki/visualization/gui/detail/package-info.java b/src/de/lmu/ifi/dbs/elki/visualization/gui/detail/package-info.java
new file mode 100644
index 00000000..3557a4fe
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/visualization/gui/detail/package-info.java
@@ -0,0 +1,27 @@
+/**
+ * <p>Classes for managing a detail view.</p>
+ *
+ */
+/*
+This file is part of ELKI:
+Environment for Developing KDD-Applications Supported by Index-Structures
+
+Copyright (C) 2011
+Ludwig-Maximilians-Universität München
+Lehr- und Forschungseinheit für Datenbanksysteme
+ELKI Development Team
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+package de.lmu.ifi.dbs.elki.visualization.gui.detail; \ No newline at end of file