summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/visualization/visualizers/AbstractVisualization.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/visualization/visualizers/AbstractVisualization.java')
-rw-r--r--src/de/lmu/ifi/dbs/elki/visualization/visualizers/AbstractVisualization.java188
1 files changed, 188 insertions, 0 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/visualization/visualizers/AbstractVisualization.java b/src/de/lmu/ifi/dbs/elki/visualization/visualizers/AbstractVisualization.java
new file mode 100644
index 00000000..c91a48e0
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/visualization/visualizers/AbstractVisualization.java
@@ -0,0 +1,188 @@
+package de.lmu.ifi.dbs.elki.visualization.visualizers;
+/*
+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 org.w3c.dom.Element;
+
+import de.lmu.ifi.dbs.elki.result.Result;
+import de.lmu.ifi.dbs.elki.result.ResultListener;
+import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
+import de.lmu.ifi.dbs.elki.visualization.visualizers.events.ContextChangeListener;
+import de.lmu.ifi.dbs.elki.visualization.visualizers.events.ContextChangedEvent;
+import de.lmu.ifi.dbs.elki.visualization.visualizers.events.ResizedEvent;
+
+/**
+ * Abstract base class for visualizations.
+ *
+ * @author Erich Schubert
+ */
+public abstract class AbstractVisualization implements Visualization, ContextChangeListener, ResultListener {
+ /**
+ * The visualization task we do.
+ */
+ protected final VisualizationTask task;
+
+ /**
+ * Our context
+ */
+ protected final VisualizerContext context;
+
+ /**
+ * The plot we are attached to
+ */
+ protected final SVGPlot svgp;
+
+ /**
+ * Pending redraw
+ */
+ protected Runnable pendingRedraw = null;
+
+ /**
+ * Layer storage
+ */
+ protected Element layer;
+
+ /**
+ * Constructor.
+ *
+ * @param task Visualization task
+ */
+ public AbstractVisualization(VisualizationTask task) {
+ super();
+ this.task = task;
+ this.context = task.getContext();
+ this.svgp = task.getPlot();
+ this.layer = null;
+ }
+
+ @Override
+ public void destroy() {
+ context.removeContextChangeListener(this);
+ context.removeResultListener(this);
+ }
+
+ @Override
+ public Element getLayer() {
+ if(layer == null) {
+ incrementalRedraw();
+ }
+ return layer;
+ }
+
+ /**
+ * Get the width
+ *
+ * @return the width
+ */
+ protected double getWidth() {
+ return task.getWidth();
+ }
+
+ /**
+ * Get the height
+ *
+ * @return the height
+ */
+ protected double getHeight() {
+ return task.getHeight();
+ }
+
+ @Override
+ public void contextChanged(ContextChangedEvent e) {
+ if(testRedraw(e)) {
+ synchronizedRedraw();
+ }
+ }
+
+ /**
+ * Override this method to add additional redraw triggers!
+ *
+ * @param e Event
+ * @return Test result
+ */
+ protected boolean testRedraw(ContextChangedEvent e) {
+ if(e instanceof ResizedEvent) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Trigger a redraw, but avoid excessive redraws.
+ */
+ protected final void synchronizedRedraw() {
+ Runnable pr = new Runnable() {
+ @Override
+ public void run() {
+ if(AbstractVisualization.this.pendingRedraw == this) {
+ AbstractVisualization.this.pendingRedraw = null;
+ AbstractVisualization.this.incrementalRedraw();
+ }
+ }
+ };
+ pendingRedraw = pr;
+ svgp.scheduleUpdate(pr);
+ }
+
+ /**
+ * Redraw the visualization (maybe incremental).
+ *
+ * Optional - by default, it will do a full redraw, which often is faster!
+ */
+ protected void incrementalRedraw() {
+ Element oldcontainer = null;
+ if(layer != null && layer.hasChildNodes()) {
+ oldcontainer = layer;
+ layer = (Element) layer.cloneNode(false);
+ }
+ redraw();
+ if(oldcontainer != null && oldcontainer.getParentNode() != null) {
+ oldcontainer.getParentNode().replaceChild(layer, oldcontainer);
+ }
+ }
+
+ /**
+ * Perform a full redraw.
+ */
+ protected abstract void redraw();
+
+ @SuppressWarnings("unused")
+ @Override
+ public void resultAdded(Result child, Result parent) {
+ // Ignore by default
+ }
+
+ @Override
+ public void resultChanged(Result current) {
+ // Default is to redraw when the result we are attached to changed.
+ if(task.getResult() == current) {
+ synchronizedRedraw();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @Override
+ public void resultRemoved(Result child, Result parent) {
+ // Ignore by default.
+ }
+} \ No newline at end of file