diff options
author | Andrej Shadura <andrewsh@debian.org> | 2019-03-09 22:30:28 +0000 |
---|---|---|
committer | Andrej Shadura <andrewsh@debian.org> | 2019-03-09 22:30:28 +0000 |
commit | cde76aeb42240f7270bc6605c606ae07d2dc5a7d (patch) | |
tree | c3ebf1d7745224f524da31dbabc5d76b9ea75916 /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.java | 302 | ||||
-rw-r--r-- | src/de/lmu/ifi/dbs/elki/visualization/gui/detail/package-info.java | 27 |
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 |