/* * TouchGraph Software License * * * Copyright (c) 2001 Alexander Shapiro. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by * TouchGraph (http://www.touchgraph.com/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The name "TouchGraph" must not be used to endorse or promote * products derived from this software without prior written * permission. For written permission, please contact * alex@touchgraph.com * * 5. Products derived from this software may not be called "TouchGraph", * nor may "TouchGraph" appear in their name, without prior written * permission of TouchGraph. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ===================================================================== * */ package com.touchgraph.graphlayout.interaction; import com.touchgraph.graphlayout.*; import java.awt.event.*; import javax.swing.*; /** HyperScroll. Responsible for producing that neat hyperbolic effect. * (Which isn't really hyperbolic, but just non-linear). * Demonstrates the usefulness of Lenses. * * @author Alexander Shapiro * @version 1.06 */ public class HyperScroll implements GraphListener { private JScrollBar hyperSB; private TGPanel tgPanel; HyperLens hyperLens; double inverseArray[]=new double[200]; //Helps calculate the inverse of the Hyperbolic function double width; //Initially was intended to change the function of the lens depending on screen size, //but now functions as a constant. public HyperScroll(TGPanel tgp) { tgPanel=tgp; hyperSB = new JScrollBar(JScrollBar.HORIZONTAL, 0, 8, 0, 108); hyperSB.addAdjustmentListener(new hyperAdjustmentListener()); hyperLens = new HyperLens(); width= 2000;//tgPanel.getSize().width/2; updateInverseArray(); tgPanel.addGraphListener(this); } public JScrollBar getHyperSB() { return hyperSB; } public HyperLens getLens() { return hyperLens; } public void graphMoved() {} //From GraphListener interface public void graphReset() { hyperSB.setValue(0); } //From GraphListener interface private class hyperAdjustmentListener implements AdjustmentListener { public void adjustmentValueChanged(AdjustmentEvent e) { updateInverseArray(); tgPanel.repaintAfterMove(); } } double rawHyperDist (double dist) { //The hyperbolic transform if(hyperSB.getValue()==0) return dist; double hyperV=hyperSB.getValue(); return Math.log(dist/(Math.pow(1.5,(70-hyperV)/40)*80) +1); /* double hyperD = Math.sqrt(dist+(10.1-Math.sqrt(hyperV)))-Math.sqrt(10.1-Math.sqrt(hyperV)); */ } double hyperDist (double dist) { double hyperV=hyperSB.getValue(); //Points that are 250 away from the center stay fixed. double hyperD= rawHyperDist(dist)/rawHyperDist(250)*250; double fade=hyperV; double fadeAdjust=100; hyperD=hyperD*fade/fadeAdjust+dist*(fadeAdjust-fade)/fadeAdjust; return hyperD; } void updateInverseArray(){ double x; for(int i=0;i<200;i++) { x=width*i/200; //Points within a radius of 'width' will have exact inverses. inverseArray[i]=hyperDist(x); } }; int findInd(int min, int max, double dist) { int mid=(min+max)/2; if (inverseArray[mid]<dist) if (max-mid==1) return max; else return findInd(mid,max,dist); else if (mid-min==1) return mid; else return findInd(min,mid,dist); } double invHyperDist (double dist) { //The inverse of hyperDist if (dist==0) return 0; int i; if (inverseArray[199]<dist) i=199; else i=findInd(0,199,dist); double x2=inverseArray[i]; double x1=inverseArray[i-1]; double j= (dist-x1)/(x2-x1); return(((double) i+j-1)/200.0*width); } class HyperLens extends TGAbstractLens { protected void applyLens(TGPoint2D p) { double dist=Math.sqrt(p.x*p.x+p.y*p.y); if(dist>0) { p.x=p.x/dist*hyperDist(dist); p.y=p.y/dist*hyperDist(dist); } else { p.x =0; p.y=0;} } protected void undoLens(TGPoint2D p) { double dist=Math.sqrt(p.x*p.x+p.y*p.y); if(dist>0) { p.x=p.x/dist*invHyperDist(dist); p.y=p.y/dist*invHyperDist(dist); } else { p.x =0; p.y=0;} } } //Things can't get much more complex then this, if you don't use an inverse function /* class HyperLens extends TGAbstractLens { protected void applyLens(TGPoint2D p) { if(p.x!=0) p.x=p.x/Math.sqrt(Math.abs(p.x))*Math.sqrt(tgPanel.getSize().width/2); if(p.y!=0) p.y=p.y/Math.sqrt(Math.abs(p.y))*Math.sqrt(tgPanel.getSize().height/2); } protected void undoLens(TGPoint2D p) { p.x=(p.x/Math.sqrt(tgPanel.getSize().width/2)); p.x=p.x*Math.abs(p.x); p.y=(p.y/Math.sqrt(tgPanel.getSize().height/2)); p.y=p.y*Math.abs(p.y); } } */ } // end com.touchgraph.graphlayout.interaction.HyperScroll