├── .classpath ├── .gitattributes ├── .gitignore ├── .project ├── CHANGELOG.md ├── LICENSE_GPL.txt ├── README.md ├── config ├── DiscardedFields.txt ├── EnvDATA-variables.csv └── RememberedHeaders.txt ├── lib ├── GLGraphics.jar ├── apple.jar ├── commons-lang3-3.11.jar ├── commons-math3-3.6.1.jar ├── core.jar ├── gicentreUtils.jar ├── gluegen-rt-natives-linux-aarch64.jar ├── gluegen-rt-natives-linux-amd64.jar ├── gluegen-rt-natives-linux-armv6.jar ├── gluegen-rt-natives-linux-armv6hf.jar ├── gluegen-rt-natives-linux-i586.jar ├── gluegen-rt-natives-macosx-universal.jar ├── gluegen-rt-natives-solaris-amd64.jar ├── gluegen-rt-natives-solaris-i586.jar ├── gluegen-rt-natives-windows-amd64.jar ├── gluegen-rt-natives-windows-i586.jar ├── gluegen-rt.jar ├── jaretutil-0.32.jar ├── javafx-swt.jar ├── javafx.base.jar ├── javafx.controls.jar ├── javafx.fxml.jar ├── javafx.graphics.jar ├── javafx.media.jar ├── javafx.swing.jar ├── javafx.web.jar ├── jcodec-0.1.6.jar ├── joda-time-2.10.10.jar ├── jogl-all-natives-linux-aarch64.jar ├── jogl-all-natives-linux-amd64.jar ├── jogl-all-natives-linux-armv6.jar ├── jogl-all-natives-linux-armv6hf.jar ├── jogl-all-natives-linux-i586.jar ├── jogl-all-natives-macosx-universal.jar ├── jogl-all-natives-solaris-amd64.jar ├── jogl-all-natives-solaris-i586.jar ├── jogl-all-natives-windows-amd64.jar ├── jogl-all-natives-windows-i586.jar ├── jogl-all.jar ├── json4processing.jar ├── log4j-1.2.15.jar ├── miglayout-core-4.2.jar ├── miglayout-swing-4.2.jar ├── opencsv-5.3.jar ├── processing-core-3.5.4.jar ├── timebars-1.49.jar └── unfolding.0.9.9.jar ├── public-data ├── Turkey-Vulture-Acopian-Center-USA-GPS-flagged-newUplift-Dec2013.csv ├── albatross-normal-tracks-9track-tailcrosswind-2020.csv └── albatross-normal-tracks-9track-tailcrosswind.csv ├── repo-resources ├── animation.gif ├── banner.png ├── case-study1.gif ├── case-study2.gif ├── lines.gif ├── npp.gif └── vec.gif ├── resources ├── logo1024.png ├── logo32.png ├── logo32e.png └── move_ucsb.png └── src ├── data ├── CustomCSVReader.java ├── CustomOutputStream.java ├── LoadDataToJTable.java ├── LoadDiscardFields.java ├── LoadEnvFieldsFromCSV.java └── LoadKnownDataHeaders.java ├── gui ├── BaseMapPanel.java ├── CombinedControlPanel.java ├── ControlPanel.java ├── DataPanel.java ├── GradientEditor.java ├── LegendPanel.java ├── LinePanel.java ├── PointPanel.java ├── RangeSlider.java ├── RangeSliderUI.java ├── TimeLine.java ├── VectorPanel.java └── WideComboBox.java ├── main ├── Colors.java ├── DesktopPane.java ├── Histo.java ├── Legend.java ├── Recorder.java ├── SequenceEncoder.java ├── Sketch.java └── SketchData.java └── utils ├── Attributes.java ├── Field.java ├── PointRecord.java └── Track.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.csv filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Files and folders in .gitignore are not tracked by Git 2 | 3 | # Visual Studio/VS Code Files 4 | .vs/ 5 | .vscode/ 6 | *.code-workspace 7 | 8 | # Binaries 9 | /bin 10 | 11 | # Export location 12 | /export 13 | 14 | # Data directory 15 | /data 16 | 17 | # Remembered headers file 18 | /config/RememberedHeaders.txt -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | DynamoVis 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | 19 | 1613644797210 20 | 21 | 30 22 | 23 | org.eclipse.core.resources.regexFilterMatcher 24 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGES 2 | 3 | ### Project Name: `DynamoVis` 4 | 5 | ##### `1.0.2` - 2023/10/27 6 | - Updating to work on Java 17, which is the latest Java version supported by Processing, as well as fixing some Mac specific issues. Tested on M1 Mac on macOS 14.0. 7 | - Processing issue which occurs on Mac with later updates was addressed (see https://github.com/benfry/processing4/issues/544). 8 | - Also removed unnecessary Mac specific fullscreen code, which sometimes causes issues with later Java versions. 9 | 10 | ##### `1.0.1` - 2023/05/25 11 | - Updated DesktopPane to call on java.awt.Taskbar module, which is supported by later versions of Java, rather than com.apple.eawt, which is no longer supported 12 | 13 | ##### `1.0` - 2021/08/01 14 | - Renamed MacOS menubar title to "DynamoVis" 15 | - Renamed "Configure Animation" to "Input Data and Animation Configuration" 16 | - Renamed Control Panel entry "Line Thickness" under Tracks to "Line Width" 17 | - Moved Control Panel field "Underlay" under "Tracks" 18 | - Public release as 1.0 19 | 20 | ##### 0.4.2.5 - 2021/05/24 21 | - Removed base encoding and framerate dropdowns from Recorder window 22 | - Unchecked 'Store frames' option in Recorder window only deletes the associated recording session's frames 23 | - Closing the Recorder window discards the recording and resets the time 24 | 25 | ##### 0.4.2.4 - 2021/05/12 26 | - Added help box back 27 | - Changed the maximum value of underlay opacity from 255 to 100 to make it more intuitive 28 | 29 | ##### 0.4.2.3 - 2021/04/23 30 | - Changing base map changes both left and right maps if we repeat the map display for edge cases 31 | - Date outlier filter now takes into account of the current year and filters dates 20 years out 32 | 33 | ##### 0.4.2.2 - 2021/04/10-12 34 | - "data" or "public-data" as the default data directories. 35 | - Higher resolution app icon for MacOS 36 | - Processing 4 libraries for MacOS integration 37 | - Fixed a bug when closing animation window freezes the app in MacOS 38 | 39 | ##### `0.4.2-alpha.1` - 2021/04/07 40 | - Empty fields in the dataset for latitude,longitude, and time skips the whole row 41 | - Empty fields in the dataset for additional fields are marked as NaN. 42 | - Changed maximum values for interval values in data configuration window to [1000, 59, 59] for [hours, minutes, seconds], respectively. 43 | - Legend improvements for poit and vector renderings. 44 | - Gradient picker is disabled when "Tag" field is selected. 45 | - Improved control panel rendering: arrows and labels, packing, glitches 46 | - JAR export finds resources. 47 | - Exported as .jar file for alpha release. 48 | 49 | ##### 0.4.2 - 2021/03/31 50 | - "New" menu item displays an appropriate text in the animation window. 51 | - Map repeats for dataset at the edge of the map. 52 | - Legend reacts correctly to repeating maps. 53 | - Smooth pan and zoom are disabled when map is repeated. 54 | - Cleaned unused source files 55 | - Added Move@ucsb logo to exported videos. 56 | 57 | ##### 0.4.1.7 - 2021/03/25 58 | - Control panel toggles won't resize the data config window. 59 | - Loading second data file does not cause a crash now. 60 | - Data config window gets disabled once we have an animation window running. 61 | - Refined legend in sketch rendering. 62 | - Cancelling the prompt window for essential header fields aborts data loading all together (including time formatting). 63 | - Prompt window for time formatting includes details. 64 | - Remembers the names of the required header fields and time formatting after asking one time. Its database is located in './config/RememberedHeaders.txt' 65 | 66 | ##### 0.4.1.6 - 2021/03/19 67 | - "New" from task bar minimizes sketch window only 68 | - OpenGl thread does not linger on exit 69 | - Moved icons to "resources" folder 70 | - Export location changed to "export" in the root folder 71 | - "Store frames" checkbox in the Record view to either keep or delete temporary frame data 72 | - Fixed the glitchy line rendering when two consecutive locations are too close 73 | - Fixed line thickness not applying to individual vertices 74 | 75 | ##### 0.4.1.5 - 2021/03/12 76 | - Data config pane has smaller minimum width 77 | - "Create Animation" button is disabled when a sketch is already running 78 | - Data configuration panel does not crash after animation is created multiple times 79 | - Timeline is visible again after the second animation is created 80 | - Resolved a bug where the data config panel was scaling right before creating an animation 81 | - Default window locations and sizes adjusted (reset locations) 82 | - No windows are spawned outside the screen with different animation resolutions 83 | - Disabled Cancel and Help buttons for now. 84 | - Legend edits (scale, tag text cropping and wrapping). 85 | - Removed "Edit/Data Config" menubar subitem. 86 | - Removed "Help" and "Dev" menubar items 87 | - Removed disfunctional base maps 88 | 89 | ##### 0.4.1.4 - 2021/03/11 90 | - Closing Processing sketch hides timeline and control panel 91 | - Exported videos now holds "Created by DynamoVis, MoveLab@UCSB, 2021" embedded in the upper right corner. 92 | - Removed month name from the legend and made copyright statement bigger. 93 | - Changed software icons to MOVELAB icon 94 | - Sketch runs with 60fps, rather than 30fps 95 | 96 | ##### 0.4.1.3 - 2021/03/04 97 | - Closing Procesing sketch doesn't close Java Application. 98 | - Fixed PSketch title and location. Timeline and control panel positions around the map sketch. 99 | - Export video is fixed. 100 | 101 | ##### 0.4.1.2 - 2021/02/25 102 | - Changed window hiearchy slightly. We are now running the main sketch as a separate window. Configure animation window stays open (its the main window now). 103 | - Processing 3 and JFrame does not work together. Rolling back the component integrations to start fixing barebones first. 104 | - Updated to Processing 3.5.4 and Unfolding 0.9.9beta 105 | 106 | ##### 0.4.1.1 - 2021/02/20 107 | - EnvDATA-variables.csv in Config reformatted as UTF-8 108 | - Merged all components from Kate, Nathan, and Pinki 109 | 110 | ##### 0.4.1.0 - 2021/02/10 111 | - Mert started working on integration of all releases 112 | - Project name changed to DynamoVis 113 | - Started running with **Java 15.0.2.7** 114 | - Upgraded libraries: commons-math3 3.3 to 3.6.1, joda-time 2.3 to 2.10.10, opencsv 2.3 to 5.3 (added commons-lang3 3.11 for opencsv 5.3) 115 | 116 | ### Project Name: `DYNAMO` 117 | ##### 0.4.0.4 - 2020/11/22 118 | - Pushed date outlier filter from 2020 to 2040 119 | 120 | ##### 0.4.0.3 - 2015/04/30 121 | - Fixed bug where end points of scale wouldn't appear when fields have aliases 122 | 123 | ##### 0.4.0.2 - 2015/01/25 124 | - Larger default legend 125 | - Points lying directly on the hour are now displayed at the correct time 126 | 127 | ##### 0.4.0.1 - 2014/11/26 128 | - New name 129 | - Minor bug fix 130 | 131 | ### Project Name: `mb_AnimationTool` 132 | ##### 0.4.0.0 - 2014/11/17 133 | - rewrite of backend to support future development and new modules 134 | - new PointRecord & Track and Field & Attributes classes 135 | - New track underlay option 136 | 137 | ##### 0.3.0.4 - 2014/09/30 138 | - New dataprocessing on data load, results shown in status box: 139 | - Tells user number of dates before 1800 and after 2020 ignored. 140 | - Warns of any dates before 1980 and after the current system date, but these are kept. 141 | - Tells user number of records marked as outliers (false in visible field) 142 | - Tells user number of records with bad coordinates (this and outliers were already discarded behind the scenes) 143 | - All timestamps are now properly parsed as UTC again. 144 | - Build animation button disabled when interval is 0 145 | 146 | ##### 0.3.0.2 - 2014/09/05 147 | - Changed appearance of color editor slightly 148 | - Couple minor fixes 149 | 150 | ##### 0.3.0.1 - 2014/08/22 151 | - Bug fixes 152 | - If interval is in seconds, the fade duration is set in minutes instead of hours 153 | 154 | ##### 0.3.0.0 - 2014/08/21 155 | - Individual tags can now be toggled on and off by using the checkboxes on the side of the timeline panel without rebuilding the animation. 156 | - Brushing is enabled. Click the tag's bar in the timeline panel to highlight its data on the map in cyan. 157 | - Timeline panel marker can now be used to seek (awkwardly... the marker is hard to grab, the animation doesn't pause while holding the marker, and if the animation is manually paused the time doesn't snap to the polling interval until it's unpaused again). 158 | - Separated out tracks/points/vectors: each have their own color and size range that can be set individually. The color ramp lists are shared. 159 | - New legends for point color/stroke and vector color/length 160 | - Legend layout can be saved and loaded 161 | - Data panel has quick rounding button for range values (nearest integer, down for min, up for max) 162 | - Data panel fields can be sorted 163 | - Switched to individual-local-identifier as default key 164 | - Holding shift while clicking load data button will force selection dialogs for key,long,lat,and timestamp. 165 | - Some ui changes 166 | 167 | ##### 0.2.4.0 - 2014/08/12 168 | - Overhauled color system. Big list of sequential and diverging color ramps to choose from, and you can assign a ramp to each field. Currently, these assignments are lost if you rebuild the animation. 169 | - Color ramps can be fully edited, saved, and loaded. Ramps can have as many stops as you want, and the editor was designed to work similar to the one in photoshop: click anywhere to make a new stop, drag it around to move, double click or click the color button to edit the stop color, and drag the stop down or click the delete button to remove it. 170 | - Timeline panel now updates marker during animation 171 | - Program now tries a few different timestamp formats before giving up and asking 172 | - Program can now handle different timestamp formats in the same dataset in the case where a user may have merged them from different sources. 173 | - Animation Interval can now be shorter than one minute 174 | - Timestamp on legend is shorter (will add ms again if/when we allow intervals to be that short) 175 | 176 | ##### 0.2.3.0 - 2014/08/05 177 | - Added basemap provider selections. Need jre 1.7+ to access google providers. Some providers won't load at extreme zooms (Bison data), but the program won't crash if this happens. 178 | - Auto-discarded fields moved to accessible file in config folder, letting user edit as necessary 179 | - Data fields with "user:" prefix are selected for the animation by default 180 | - Window locations are now saved between animations, reset layout button in menu enabled 181 | - Fixed recording panel breaking when animation is rebuilt 182 | - All prompts should now be centered over their parent 183 | - Removed some redundant calculations during animation building process 184 | - Intervals now round up to nearest whole minute 185 | 186 | ##### 0.2.2.0 - 2014/08/03 187 | - Quick fix to diverging color ramp calculation 188 | - Added progress monitors for data loading/processing 189 | - Implemented basic video export tool. Lets you start and stop recording, then save to an h.264 mp4. Haven't tested thoroughly, and temp files are not automatically deleted. 190 | 191 | ##### 0.2.1.1 - 2014/07/31 192 | - Minor bug fixes 193 | - List of auto discarded fields will now match to the older datasets 194 | - Datetime formatter prompt moved to a looping try catch block (it won't go away until it can successfully parse a datetime) 195 | 196 | ##### 0.2.1.0 - 2014/07/30 197 | - Rebuilt GUI again for compatability with mac's lightweight/heavyweight rendering issues 198 | - Excessive zooming at start is fixed 199 | - An "overview" timeline of the tags is created, will eventually have seeking/brushing interactivity 200 | - Color and legend editing panels implemented, but gradients are limited due to HSB color space and some wonky calculations 201 | - Min/max ranges for each field are editable in the data panel - need to add a quick rounding button 202 | - Rudimentary "point vectors" option added. This option is only available if the data has an obvious directional field (360 degrees with a bit of tolerance). Basic white lines are drawn from each data point with lengths scaled to another field. User interface for this needs to be improved, as well as more visual options. 203 | 204 | ##### 0.2.0.0 - 2014/07/13 205 | - Overhaul to data structure and gui 206 | - Reads raw Movebank CSV's: works with sets that have some bad data/coords 207 | - Data configuration panel implemented: lets user enable/disable/rename fields and filter tags 208 | - Program attempts to determine an appropriate time interval for the dataset (mode), but user can override. 209 | - Matches data fields from the big list of env-data fields, enables them by default, and pulls units and misc info 210 | + Some fields are discarded in preprocessing and won't be available: anything nominal especially 211 | - Sketch should start zoomed to the extent of data points (but doesn't always...) 212 | - A few options for animation size + custom res (must be done during new/edit) 213 | - Existing animation/data can be tweaked with edit menu (animation is then rebuilt) 214 | - Processing 2.2.1 Core 215 | - Unfolding 0.9.6 216 | 217 | ##### 0.1.3.0 - 2014/05/23 218 | - Rebuilding with EE 1.6 219 | - Latest JOGL libraries (previous ones were failing in OS X) 220 | - Some UI changes for OS X 221 | 222 | ##### 0.1.2.1 - 2014/05/21 223 | - Added button to swap datasets. If the csv isn't formatted properly it will probably fail super ungracefully 224 | - Changed tag id color symbology method to use an array so it will work for other data. 225 | - Commented up the source 226 | 227 | ##### 0.1.2.0 - 2014/05/20 228 | - Added class to parse CSV to an Unfolding Feature set. CSV needs longitude, latitude, timestamp, and tag_local_identifier, although we can make this more flexible 229 | - Works with a modified Turkey Vulture dataset, but not very well unless you cut down the number of birds to 1 or 2. 230 | 231 | ##### 0.1.1.0 - 2014/05/19 232 | - Finished removing all Galapagos stuff 233 | - Rebuilt the CP5 GUI in Swing, breaking backwards compatability with the Processing IDE 234 | 235 | ##### 0.1.0.0 - 2014/05/18 236 | - Removed most of the static GalapagosSketchTest code 237 | - Added field select dropdowns for each visual variable 238 | - Only has one color gradient + colors for tags 239 | 240 | -------- 241 | 242 | # KNOWN ISSUES 243 | - Malfunctioned data lines prevents loading the whole datafile (bisbing_mig.csv) 244 | - Barscale in legend becomes too long closer to poles 245 | - Occasional line between repeated maps on some zoom levels. 246 | - Timeline checkboxes does not react to Shift/Ctrl+click well. 247 | 248 | # TO-DO: 249 | - Pending library upgrades 250 | - miglayout 4.2 (5.0 available) 251 | - log4j 1.2.15 (2.14.1 available but Unfolding Maps uses 1.2.15) 252 | - jcodec 0.1.6 (0.2.5 available but drastically changes the encoding method) 253 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DynamoVis 2 | 3 | 6 | 7 | test
8 | 9 |
10 | 11 | **DynamoVis** is a data visualization software specifically targeted for spatiotemporal movement data. It is developed by [Move Lab @ UC Santa Barbara](https://move.geog.ucsb.edu/) and designed to be accessible and easily usable for scientists without extensive prior experience with programming, GIS software, or custom data visualization tools. The intuitive design focuses on a simple interface for scientists to apply spatial data visualization techniques, giving ecologists and biologists of all backgrounds the power to visualize complicated spatial patterns. 12 | 13 | > Dodge, S., Toka, M. & Bae, C.J. DynamoVis 1.0: an exploratory data visualization software for mapping movement in relation to internal and external factors. Mov Ecol 9, 55 (2021). https://doi.org/10.1186/s40462-021-00291-5 14 | 15 |
16 | 17 | test
18 | 19 |
20 |
- An animation of the user interface using Galapagos Albatross movement data with various basemaps and visualization parameters.
21 |
22 | 23 | ## Dynamovis Web 24 | **Dynamovis Web** is now available in Beta version. Please visit Dynamovis Web here : https://dynamovis.geog.ucsb.edu/ 25 | 26 | ## Usage Dynamovis Desktop 27 | 0. Make sure to have [Java 17 installed](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) and set up in your system or user PATH. 28 | - To check Java version, start Terminal and type `java -version`. The version listed should be 17. 29 | 2. Download the latest release (`DynamoVis-1.0.2.zip`) [here](https://github.com/move-ucsb/DynamoVis/releases). 30 | 3. Unzip the folder anywhere on your machine. 31 | 4. Double-click on `DynamoVis.jar` 32 | - If this doesn't do anything: 33 | - (Windows) Double-click on `run_windows.bat` 34 | - (macOS) Start Terminal, type `cd ` (with a white space). Drag and drop the DynamoVis folder on the terminal window and press enter. Type `./run_unix.sh` or `bash run_unix.sh`and press enter. 35 | 36 | 5. If your system shows a security pop up from an unidentified developer, it is safe to ignore it. 37 | - (Windows) On the security pop up `More info -> Run anyway`. 38 | - (macOS) Click `OK` on the security pop up to close it. Then go into your `System Preferences > Security & Privacy` and then click `Open Anyway` next to the message that `DynamoVis.jar` was blocked. 39 | 40 | 6. The DynamoVis software will open with the initial _Input Data and Animation Configuration_ and _Status_ windows. 41 | 42 |

43 | Alternatively, you can also run the jar file from Terminal using below command in extracted folder: 44 | 45 | ```shell 46 | java -jar DynamoVis.jar 47 | ``` 48 | 49 | See 'Compile from source' section below for notes on compiling the software from scratch. 50 | 51 | ## Use cases 52 | ### Turkey vulture [data set](https://doi.org/10.5441/001/1.46ft1k05) 53 | 54 | test
55 | - An exported animation of the turkey vulture Leo on Microsoft Aerial basemap. It shows the foraging behavior of Leo -- moving slowly or pausing in high-vegetation areas (NDVI), shown with bright green circles. 56 |
57 |

58 | 59 | test
60 | - Another exported track animation of turkey vulture Leo displayed on Esri World Terrain basemap. The thicker purple line visualizes thermal uplift that aids the bird to move faster. The thin underlay lines shows the prior movement of Leo, hinting its commonly-travelled routes 61 |
62 | 63 |
64 | 65 | ### Galapagos albatrosses [data set](https://doi.org/10.5441/001/1.3hp3s250) 66 | 67 |
68 |
69 | test 70 |
71 |
72 | test 73 |
74 |
75 | - An set of exported animations of one Galapagos albatross track (4264-84830852) displayed on Esri World Terrain basemap, illustrating the relationship between the movement speed and wind support. The left visualization highlights the use of higher tail-wind support (shown in blue color) for faster outbound flights (shown with thicker lines), and the right map shows the actual wind direction using vectors of variable size. 76 |
77 |

78 | 79 | test 80 |
- Another animation of the albatross (4264-84830852) displayed on the Microsoft Aerial basemap. The visualization highlights the relationship between net primary production (NPP) of the ocean and albatross movement speed. The albatross appears to move slowly (smaller point size) or make frequent stops along the coast of Peru to forage in high NPP areas (shown in darker green colors). The bird appears to fly faster (larger point size) during the flights over the ocean and around the Galapagos where ocean NPP is lower (lighter green colors). 81 |
82 |
83 | 84 | ## Config 85 | `./config/` directory stores extra files that are useful for the use case of the software. 86 | 87 | - `RememberedHeaders.txt` stores the names of the required fields for DynamoVis to function properly. Upon loading data to the software, the header names of the *unique identifier, latitiude, longitude* and *timestamp* will be recorded in this file for future reference. Successive loading of the same file will use information recorded in this file. 88 | 89 | - `EnvDATA-variables.csv` keeps the details of known fields, commonly used by [EnvData system](https://www.movebank.org/cms/movebank-content/env-data). 90 | 91 | - `DiscardedFields.txt` hold a list of columns (or fields) in the data that is discarded by DynamoVis. Feel free to add more fields in your local copy to prevent loading unnecessary fields to your animations. 92 | 93 | - `./color/` and `./legend/` folders keeps a copy of the custom color ramps and legend layouts. 94 | 95 | ## BibTex 96 | 97 | ``` 98 | @article{dodge2021dynamovis, 99 | title={DynamoVis 1.0: an exploratory data visualization software for mapping movement in relation to internal and external factors}, 100 | author={Dodge, Somayeh and Toka, Mert and Bae, Crystal J}, 101 | journal={Movement Ecology}, 102 | volume={9}, 103 | number={1}, 104 | pages={1--17}, 105 | year={2021}, 106 | publisher={Springer} 107 | } 108 | ``` 109 | 110 | ## Data 111 | We distribute copies of Galapagos Albatrosses and Turkey Vultures data sets along with the repository in `./public-data` directory. 112 | 113 | ## Project Sponsor 114 |
115 | 116 |

Award BCS # 1853681
117 | PI: Somayeh Dodge

118 |
119 | 120 | ## Contact 121 | Feel free to open an [issue](https://github.com/move-ucsb/DynamoVis/issues) in case something is wrong. Please make sure to note the description of the issue and your computer specifications (operating system, java version, error messages, etc.). 122 | 123 | ## Compile from source 124 | If you'd like to clone the repository and compile from the source, make sure to have [Git Large File System](https://git-lfs.github.com/) installed and enabled. Git-LFS is required for large `*.csv` files. If you don't want to install Git-LFS, you will need to clone the repository and manually download .csv files in `/config` and `/public-data`. 125 | 126 | ## Tested on: 127 | - Windows 10 128 | - Windows 11 129 | - macOS 10.14.6 Mojave 130 | - macOS 10.15 Catalina 131 | 132 | w/ Java 15.0.2 133 | 134 | ## List of developers 135 | - Jenni Hutson 136 | - Mert Toka 137 | - Glenn Xavier 138 | - Wing Yi (Pinki) Wong 139 | - Kate Carlson 140 | - Kin (Nathan) Chan 141 | -------------------------------------------------------------------------------- /config/DiscardedFields.txt: -------------------------------------------------------------------------------- 1 | individualtaxoncanonicalname 2 | taglocalidentifier 3 | studyname 4 | locationlat 5 | locationlong 6 | utmeasting 7 | utmnorthing 8 | utmzone 9 | timestamp 10 | studytimezone 11 | studylocaltimestamp 12 | visible 13 | behaviouralclassification 14 | comments 15 | eventid 16 | sensortype 17 | eobsbatteryvoltage 18 | eobsfixbatteryvoltage 19 | eobshorizontalaccuracyestimate 20 | eobsspeedaccuracyestimate 21 | eobsstarttimestamp 22 | eobsstatus 23 | eobstypeoffix 24 | eobsusedtimetogetfix 25 | eobskeybinchecksum -------------------------------------------------------------------------------- /config/EnvDATA-variables.csv: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:0fdb89b4dfacdafe412cb6c997252ae63a03f553c4964d2a859413cb1932e382 3 | size 191292 4 | -------------------------------------------------------------------------------- /config/RememberedHeaders.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/config/RememberedHeaders.txt -------------------------------------------------------------------------------- /lib/GLGraphics.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/GLGraphics.jar -------------------------------------------------------------------------------- /lib/apple.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/apple.jar -------------------------------------------------------------------------------- /lib/commons-lang3-3.11.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/commons-lang3-3.11.jar -------------------------------------------------------------------------------- /lib/commons-math3-3.6.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/commons-math3-3.6.1.jar -------------------------------------------------------------------------------- /lib/core.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/core.jar -------------------------------------------------------------------------------- /lib/gicentreUtils.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gicentreUtils.jar -------------------------------------------------------------------------------- /lib/gluegen-rt-natives-linux-aarch64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt-natives-linux-aarch64.jar -------------------------------------------------------------------------------- /lib/gluegen-rt-natives-linux-amd64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt-natives-linux-amd64.jar -------------------------------------------------------------------------------- /lib/gluegen-rt-natives-linux-armv6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt-natives-linux-armv6.jar -------------------------------------------------------------------------------- /lib/gluegen-rt-natives-linux-armv6hf.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt-natives-linux-armv6hf.jar -------------------------------------------------------------------------------- /lib/gluegen-rt-natives-linux-i586.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt-natives-linux-i586.jar -------------------------------------------------------------------------------- /lib/gluegen-rt-natives-macosx-universal.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt-natives-macosx-universal.jar -------------------------------------------------------------------------------- /lib/gluegen-rt-natives-solaris-amd64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt-natives-solaris-amd64.jar -------------------------------------------------------------------------------- /lib/gluegen-rt-natives-solaris-i586.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt-natives-solaris-i586.jar -------------------------------------------------------------------------------- /lib/gluegen-rt-natives-windows-amd64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt-natives-windows-amd64.jar -------------------------------------------------------------------------------- /lib/gluegen-rt-natives-windows-i586.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt-natives-windows-i586.jar -------------------------------------------------------------------------------- /lib/gluegen-rt.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/gluegen-rt.jar -------------------------------------------------------------------------------- /lib/jaretutil-0.32.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jaretutil-0.32.jar -------------------------------------------------------------------------------- /lib/javafx-swt.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/javafx-swt.jar -------------------------------------------------------------------------------- /lib/javafx.base.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/javafx.base.jar -------------------------------------------------------------------------------- /lib/javafx.controls.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/javafx.controls.jar -------------------------------------------------------------------------------- /lib/javafx.fxml.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/javafx.fxml.jar -------------------------------------------------------------------------------- /lib/javafx.graphics.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/javafx.graphics.jar -------------------------------------------------------------------------------- /lib/javafx.media.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/javafx.media.jar -------------------------------------------------------------------------------- /lib/javafx.swing.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/javafx.swing.jar -------------------------------------------------------------------------------- /lib/javafx.web.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/javafx.web.jar -------------------------------------------------------------------------------- /lib/jcodec-0.1.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jcodec-0.1.6.jar -------------------------------------------------------------------------------- /lib/joda-time-2.10.10.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/joda-time-2.10.10.jar -------------------------------------------------------------------------------- /lib/jogl-all-natives-linux-aarch64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all-natives-linux-aarch64.jar -------------------------------------------------------------------------------- /lib/jogl-all-natives-linux-amd64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all-natives-linux-amd64.jar -------------------------------------------------------------------------------- /lib/jogl-all-natives-linux-armv6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all-natives-linux-armv6.jar -------------------------------------------------------------------------------- /lib/jogl-all-natives-linux-armv6hf.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all-natives-linux-armv6hf.jar -------------------------------------------------------------------------------- /lib/jogl-all-natives-linux-i586.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all-natives-linux-i586.jar -------------------------------------------------------------------------------- /lib/jogl-all-natives-macosx-universal.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all-natives-macosx-universal.jar -------------------------------------------------------------------------------- /lib/jogl-all-natives-solaris-amd64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all-natives-solaris-amd64.jar -------------------------------------------------------------------------------- /lib/jogl-all-natives-solaris-i586.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all-natives-solaris-i586.jar -------------------------------------------------------------------------------- /lib/jogl-all-natives-windows-amd64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all-natives-windows-amd64.jar -------------------------------------------------------------------------------- /lib/jogl-all-natives-windows-i586.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all-natives-windows-i586.jar -------------------------------------------------------------------------------- /lib/jogl-all.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/jogl-all.jar -------------------------------------------------------------------------------- /lib/json4processing.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/json4processing.jar -------------------------------------------------------------------------------- /lib/log4j-1.2.15.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/log4j-1.2.15.jar -------------------------------------------------------------------------------- /lib/miglayout-core-4.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/miglayout-core-4.2.jar -------------------------------------------------------------------------------- /lib/miglayout-swing-4.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/miglayout-swing-4.2.jar -------------------------------------------------------------------------------- /lib/opencsv-5.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/opencsv-5.3.jar -------------------------------------------------------------------------------- /lib/processing-core-3.5.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/processing-core-3.5.4.jar -------------------------------------------------------------------------------- /lib/timebars-1.49.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/timebars-1.49.jar -------------------------------------------------------------------------------- /lib/unfolding.0.9.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/lib/unfolding.0.9.9.jar -------------------------------------------------------------------------------- /public-data/Turkey-Vulture-Acopian-Center-USA-GPS-flagged-newUplift-Dec2013.csv: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:bfec44563f08a66ed1edfb34dd84b546c1b9a01cc2b40ee9d072ddf54e90f32c 3 | size 50222554 4 | -------------------------------------------------------------------------------- /public-data/albatross-normal-tracks-9track-tailcrosswind-2020.csv: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:8c2b3212d7f6c2df4111962a6b10152ccdb97436a5238dc5b007af03ce2cc281 3 | size 3539206 4 | -------------------------------------------------------------------------------- /public-data/albatross-normal-tracks-9track-tailcrosswind.csv: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:4ffa9775950dcdae52948f5753881a367b13f2108da5209ce2b5ec7fefdd7747 3 | size 3649332 4 | -------------------------------------------------------------------------------- /repo-resources/animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/repo-resources/animation.gif -------------------------------------------------------------------------------- /repo-resources/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/repo-resources/banner.png -------------------------------------------------------------------------------- /repo-resources/case-study1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/repo-resources/case-study1.gif -------------------------------------------------------------------------------- /repo-resources/case-study2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/repo-resources/case-study2.gif -------------------------------------------------------------------------------- /repo-resources/lines.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/repo-resources/lines.gif -------------------------------------------------------------------------------- /repo-resources/npp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/repo-resources/npp.gif -------------------------------------------------------------------------------- /repo-resources/vec.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/repo-resources/vec.gif -------------------------------------------------------------------------------- /resources/logo1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/resources/logo1024.png -------------------------------------------------------------------------------- /resources/logo32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/resources/logo32.png -------------------------------------------------------------------------------- /resources/logo32e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/resources/logo32e.png -------------------------------------------------------------------------------- /resources/move_ucsb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/move-ucsb/DynamoVis/0996309447a14b82d0321e2e7c3c41083299d631/resources/move_ucsb.png -------------------------------------------------------------------------------- /src/data/CustomCSVReader.java: -------------------------------------------------------------------------------- 1 | package data; 2 | 3 | /** 4 | Copyright 2005 Bytecode Pty Ltd. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | import java.io.BufferedReader; 20 | import java.io.Closeable; 21 | import java.io.IOException; 22 | import java.io.Reader; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | import com.opencsv.CSVParser; 27 | import com.opencsv.CSVParserBuilder; 28 | import com.opencsv.enums.CSVReaderNullFieldIndicator; 29 | 30 | /** 31 | * A very simple CSV reader released under a commercial-friendly license. 32 | * 33 | * @author Glen Smith 34 | * 35 | */ 36 | 37 | // Added a count to hook for progress monitor 38 | 39 | public class CustomCSVReader implements Closeable { 40 | 41 | private BufferedReader br; 42 | 43 | private boolean hasNext = true; 44 | 45 | private CSVParser parser; 46 | 47 | private int skipLines; 48 | 49 | private boolean linesSkiped; 50 | 51 | public long readSoFar; 52 | 53 | /** 54 | * The default line to start reading. 55 | */ 56 | public static final int DEFAULT_SKIP_LINES = 0; 57 | 58 | /** 59 | * Constructs CSVReader using a comma for the separator. 60 | * 61 | * @param reader the reader to an underlying CSV source. 62 | */ 63 | public CustomCSVReader(Reader reader) { 64 | this(reader, CSVParser.DEFAULT_SEPARATOR, CSVParser.DEFAULT_QUOTE_CHARACTER, 65 | CSVParser.DEFAULT_ESCAPE_CHARACTER); 66 | } 67 | 68 | /** 69 | * Constructs CSVReader with supplied separator. 70 | * 71 | * @param reader the reader to an underlying CSV source. 72 | * @param separator the delimiter to use for separating entries. 73 | */ 74 | public CustomCSVReader(Reader reader, char separator) { 75 | this(reader, separator, CSVParser.DEFAULT_QUOTE_CHARACTER, CSVParser.DEFAULT_ESCAPE_CHARACTER); 76 | } 77 | 78 | /** 79 | * Constructs CSVReader with supplied separator and quote char. 80 | * 81 | * @param reader the reader to an underlying CSV source. 82 | * @param separator the delimiter to use for separating entries 83 | * @param quotechar the character to use for quoted elements 84 | */ 85 | public CustomCSVReader(Reader reader, char separator, char quotechar) { 86 | this(reader, separator, quotechar, CSVParser.DEFAULT_ESCAPE_CHARACTER, DEFAULT_SKIP_LINES, 87 | CSVParser.DEFAULT_STRICT_QUOTES); 88 | } 89 | 90 | /** 91 | * Constructs CSVReader with supplied separator, quote char and quote handling 92 | * behavior. 93 | * 94 | * @param reader the reader to an underlying CSV source. 95 | * @param separator the delimiter to use for separating entries 96 | * @param quotechar the character to use for quoted elements 97 | * @param strictQuotes sets if characters outside the quotes are ignored 98 | */ 99 | public CustomCSVReader(Reader reader, char separator, char quotechar, boolean strictQuotes) { 100 | this(reader, separator, quotechar, CSVParser.DEFAULT_ESCAPE_CHARACTER, DEFAULT_SKIP_LINES, strictQuotes); 101 | } 102 | 103 | /** 104 | * Constructs CSVReader with supplied separator and quote char. 105 | * 106 | * @param reader the reader to an underlying CSV source. 107 | * @param separator the delimiter to use for separating entries 108 | * @param quotechar the character to use for quoted elements 109 | * @param escape the character to use for escaping a separator or quote 110 | */ 111 | 112 | public CustomCSVReader(Reader reader, char separator, char quotechar, char escape) { 113 | this(reader, separator, quotechar, escape, DEFAULT_SKIP_LINES, CSVParser.DEFAULT_STRICT_QUOTES); 114 | } 115 | 116 | /** 117 | * Constructs CSVReader with supplied separator and quote char. 118 | * 119 | * @param reader the reader to an underlying CSV source. 120 | * @param separator the delimiter to use for separating entries 121 | * @param quotechar the character to use for quoted elements 122 | * @param line the line number to skip for start reading 123 | */ 124 | public CustomCSVReader(Reader reader, char separator, char quotechar, int line) { 125 | this(reader, separator, quotechar, CSVParser.DEFAULT_ESCAPE_CHARACTER, line, CSVParser.DEFAULT_STRICT_QUOTES); 126 | } 127 | 128 | /** 129 | * Constructs CSVReader with supplied separator and quote char. 130 | * 131 | * @param reader the reader to an underlying CSV source. 132 | * @param separator the delimiter to use for separating entries 133 | * @param quotechar the character to use for quoted elements 134 | * @param escape the character to use for escaping a separator or quote 135 | * @param line the line number to skip for start reading 136 | */ 137 | public CustomCSVReader(Reader reader, char separator, char quotechar, char escape, int line) { 138 | this(reader, separator, quotechar, escape, line, CSVParser.DEFAULT_STRICT_QUOTES); 139 | } 140 | 141 | /** 142 | * Constructs CSVReader with supplied separator and quote char. 143 | * 144 | * @param reader the reader to an underlying CSV source. 145 | * @param separator the delimiter to use for separating entries 146 | * @param quotechar the character to use for quoted elements 147 | * @param escape the character to use for escaping a separator or quote 148 | * @param line the line number to skip for start reading 149 | * @param strictQuotes sets if characters outside the quotes are ignored 150 | */ 151 | public CustomCSVReader(Reader reader, char separator, char quotechar, char escape, int line, boolean strictQuotes) { 152 | this(reader, separator, quotechar, escape, line, strictQuotes, CSVParser.DEFAULT_IGNORE_LEADING_WHITESPACE); 153 | } 154 | 155 | /** 156 | * Constructs CSVReader with supplied separator and quote char. 157 | * 158 | * @param reader the reader to an underlying CSV source. 159 | * @param separator the delimiter to use for separating entries 160 | * @param quotechar the character to use for quoted elements 161 | * @param escape the character to use for escaping a separator 162 | * or quote 163 | * @param line the line number to skip for start reading 164 | * @param strictQuotes sets if characters outside the quotes are 165 | * ignored 166 | * @param ignoreLeadingWhiteSpace it true, parser should ignore white space 167 | * before a quote in a field 168 | */ 169 | public CustomCSVReader(Reader reader, char separator, char quotechar, char escape, int line, boolean strictQuotes, 170 | boolean ignoreLeadingWhiteSpace) { 171 | this.br = new BufferedReader(reader); 172 | this.parser = new CSVParserBuilder().withSeparator(separator).withQuoteChar(quotechar).withEscapeChar(escape) 173 | .withStrictQuotes(strictQuotes).withIgnoreLeadingWhiteSpace(ignoreLeadingWhiteSpace) 174 | .withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_SEPARATORS).build(); 175 | // separator, quotechar, escape, strictQuotes, ignoreLeadingWhiteSpace); 176 | this.skipLines = line; 177 | this.readSoFar = 0; 178 | 179 | } 180 | 181 | /** 182 | * Reads the entire file into a List with each element being a String[] of 183 | * tokens. 184 | * 185 | * @return a List of String[], with each String[] representing a line of the 186 | * file. 187 | * 188 | * @throws IOException if bad things happen during the read 189 | */ 190 | public List readAll() throws IOException { 191 | 192 | List allElements = new ArrayList(); 193 | while (hasNext) { 194 | String[] nextLineAsTokens = readNext(); 195 | if (nextLineAsTokens != null) 196 | allElements.add(nextLineAsTokens); 197 | } 198 | return allElements; 199 | 200 | } 201 | 202 | /** 203 | * Reads the next line from the buffer and converts to a string array. 204 | * 205 | * @return a string array with each comma-separated element as a separate entry. 206 | * 207 | * @throws IOException if bad things happen during the read 208 | */ 209 | public String[] readNext() throws IOException { 210 | 211 | String[] result = null; 212 | do { 213 | String nextLine = getNextLine(); 214 | if (!hasNext) { 215 | return result; // should throw if still pending? 216 | } 217 | String[] r = parser.parseLineMulti(nextLine); 218 | if (r.length > 0) { 219 | if (result == null) { 220 | result = r; 221 | } else { 222 | String[] t = new String[result.length + r.length]; 223 | System.arraycopy(result, 0, t, 0, result.length); 224 | System.arraycopy(r, 0, t, result.length, r.length); 225 | result = t; 226 | } 227 | } 228 | } while (parser.isPending()); 229 | return result; 230 | } 231 | 232 | /** 233 | * Reads the next line from the file. 234 | * 235 | * @return the next line from the file without trailing newline 236 | * @throws IOException if bad things happen during the read 237 | */ 238 | private String getNextLine() throws IOException { 239 | if (!this.linesSkiped) { 240 | for (int i = 0; i < skipLines; i++) { 241 | br.readLine(); 242 | } 243 | this.linesSkiped = true; 244 | } 245 | String nextLine = br.readLine(); 246 | if (nextLine == null) { 247 | hasNext = false; 248 | } else { 249 | readSoFar += nextLine.length() + 1; 250 | } 251 | return hasNext ? nextLine : null; 252 | } 253 | 254 | /** 255 | * Closes the underlying reader. 256 | * 257 | * @throws IOException if the close fails 258 | */ 259 | public void close() throws IOException { 260 | br.close(); 261 | } 262 | 263 | } 264 | -------------------------------------------------------------------------------- /src/data/CustomOutputStream.java: -------------------------------------------------------------------------------- 1 | package data; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | import javax.swing.JTextArea; 7 | 8 | public class CustomOutputStream extends OutputStream { 9 | private JTextArea textArea; 10 | 11 | public CustomOutputStream(JTextArea textArea) { 12 | this.textArea = textArea; 13 | } 14 | 15 | @Override 16 | public void write(int b) throws IOException { 17 | // redirects data to the text area 18 | textArea.append(String.valueOf((char) b)); 19 | // scrolls the text area to the end of data 20 | textArea.setCaretPosition(textArea.getDocument().getLength()); 21 | } 22 | } -------------------------------------------------------------------------------- /src/data/LoadDiscardFields.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package data; 23 | 24 | import java.io.File; 25 | import java.io.FileNotFoundException; 26 | import java.io.FileReader; 27 | import java.io.IOException; 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | public class LoadDiscardFields { 32 | 33 | public List loadData(String fileName) { 34 | List list = new ArrayList(); 35 | CustomCSVReader reader = null; 36 | try { 37 | File file = new File(fileName); 38 | reader = new CustomCSVReader(new FileReader(file)); 39 | } catch (FileNotFoundException e2) { 40 | e2.printStackTrace(); 41 | } 42 | 43 | String row[]; 44 | try { 45 | while ((row = reader.readNext()) != null) { 46 | list.add(row[0].replace(":", "").replace("-", "").replace(".", "")); 47 | } 48 | } catch (IOException e) { 49 | e.printStackTrace(); 50 | } 51 | 52 | try { 53 | reader.close(); 54 | } catch (IOException e) { 55 | e.printStackTrace(); 56 | } 57 | 58 | return list; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/data/LoadEnvFieldsFromCSV.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package data; 23 | 24 | import java.io.FileNotFoundException; 25 | import java.io.IOException; 26 | import java.nio.charset.StandardCharsets; 27 | import java.nio.file.Files; 28 | import java.nio.file.Path; 29 | import java.nio.file.Paths; 30 | import java.util.ArrayList; 31 | 32 | import com.opencsv.CSVParser; 33 | import com.opencsv.CSVReader; 34 | import com.opencsv.CSVReaderBuilder; 35 | import com.opencsv.exceptions.CsvValidationException; 36 | 37 | 38 | public class LoadEnvFieldsFromCSV { 39 | 40 | public ArrayList> loadData(String fileName) { 41 | ArrayList> data = new ArrayList>(); 42 | 43 | CSVReader reader = null; 44 | try { 45 | Path path = Paths.get(fileName); 46 | reader = new CSVReaderBuilder(Files.newBufferedReader(path, StandardCharsets.UTF_8)).withCSVParser(new CSVParser()).build(); 47 | } catch (FileNotFoundException e2) { 48 | e2.printStackTrace(); 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | } 52 | String[] header = null; 53 | try { 54 | header = reader.readNext(); 55 | } catch (IOException e1) { 56 | e1.printStackTrace(); 57 | } catch (CsvValidationException e) { 58 | e.printStackTrace(); 59 | } 60 | if (header == null) { 61 | throw new RuntimeException("No header"); 62 | } 63 | 64 | String[] row; 65 | // int i = 0; 66 | try { 67 | while ((row = reader.readNext()) != null) { 68 | // i++; 69 | 70 | String fieldFull = row[0] + " "; 71 | if (!row[1].equals("N/A")) { 72 | fieldFull = fieldFull + row[1] + " "; 73 | } 74 | fieldFull = fieldFull + row[2]; 75 | String fieldShort = row[2]; 76 | String units = row[3].replace("^-2", "\u00b2").replace("^-3", "\u00b3"); 77 | ArrayList temp = new ArrayList(); 78 | temp.add(fieldFull); 79 | temp.add(fieldShort); 80 | temp.add(units); 81 | data.add(temp); 82 | } 83 | 84 | } catch (IOException e) { 85 | e.printStackTrace(); 86 | } catch (CsvValidationException e) { 87 | e.printStackTrace(); 88 | } 89 | try { 90 | reader.close(); 91 | } catch (IOException e) { 92 | e.printStackTrace(); 93 | } 94 | return data; 95 | 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/data/LoadKnownDataHeaders.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package data; 23 | 24 | import java.io.BufferedWriter; 25 | import java.io.File; 26 | import java.io.FileNotFoundException; 27 | import java.io.FileReader; 28 | import java.io.FileWriter; 29 | import java.io.IOException; 30 | import java.io.Writer; 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | 34 | public class LoadKnownDataHeaders { 35 | private String filename; 36 | private List list; 37 | 38 | public LoadKnownDataHeaders (String fn) { 39 | this.filename = fn; 40 | list = new ArrayList(); 41 | loadData(); 42 | } 43 | 44 | // read 45 | public boolean loadData() { 46 | CustomCSVReader reader = null; 47 | try { 48 | File file = new File(filename); 49 | reader = new CustomCSVReader(new FileReader(file)); 50 | } catch (FileNotFoundException e2) { 51 | e2.printStackTrace(); 52 | return false; 53 | } 54 | 55 | String row[]; 56 | // HEADER 57 | // filename, fieldfortag, fieldforlong, fieldforlat, fieldfortime, timeformat 58 | // row[0], row[1], row[2], row[3], row[4], row[5] 59 | try { 60 | while ((row = reader.readNext()) != null) { 61 | list.add(new String[] { row[0], row[1], row[2], row[3], row[4], row[5] } ); 62 | } 63 | } catch (IOException e) { 64 | e.printStackTrace(); 65 | return false; 66 | } 67 | 68 | try { 69 | reader.close(); 70 | return true; 71 | } catch (IOException e) { 72 | e.printStackTrace(); 73 | return false; 74 | } 75 | } 76 | 77 | // check 78 | public String[] queryFilename(String fname) { 79 | // see if it already exists 80 | for (String[] strings : list) { 81 | if(fname.equals(strings[0])) return strings; 82 | } 83 | return null; 84 | } 85 | 86 | // write 87 | public void keepInfoIfMissing(String fname, 88 | String tag, String longitude, String latitude, 89 | String time, String timeformat) { 90 | 91 | // see if it already exists 92 | if(queryFilename(fname) == null) { 93 | // if not, write it in the file 94 | Writer output = null; 95 | try { 96 | output = new BufferedWriter(new FileWriter(filename, true)); 97 | } catch (FileNotFoundException e) { 98 | e.printStackTrace(); 99 | } catch (IOException e) { 100 | e.printStackTrace(); 101 | } 102 | 103 | try { 104 | StringBuilder sb = new StringBuilder(); 105 | sb.append(fname);sb.append(','); 106 | sb.append(tag);sb.append(','); 107 | sb.append(longitude);sb.append(','); 108 | sb.append(latitude);sb.append(','); 109 | sb.append(time);sb.append(','); 110 | sb.append(timeformat);sb.append('\n'); 111 | 112 | output.append(sb.toString()); 113 | output.close(); 114 | } catch (IOException e) { 115 | e.printStackTrace(); 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/gui/BaseMapPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package gui; 23 | 24 | import java.awt.event.ActionEvent; 25 | import java.awt.event.ActionListener; 26 | import java.util.Map; 27 | import java.util.Map.Entry; 28 | import java.util.TreeMap; 29 | 30 | import javax.swing.ButtonGroup; 31 | import javax.swing.JPanel; 32 | 33 | import main.DesktopPane; 34 | import net.miginfocom.swing.MigLayout; 35 | 36 | import javax.swing.JRadioButton; 37 | 38 | import de.fhpotsdam.unfolding.providers.AbstractMapProvider; 39 | import de.fhpotsdam.unfolding.providers.EsriProvider; 40 | import de.fhpotsdam.unfolding.providers.Google; 41 | // import de.fhpotsdam.unfolding.providers.MapBox; 42 | // import de.fhpotsdam.unfolding.providers.MapQuestProvider; 43 | import de.fhpotsdam.unfolding.providers.Microsoft; 44 | // import de.fhpotsdam.unfolding.providers.Yahoo; 45 | 46 | @SuppressWarnings("serial") 47 | public class BaseMapPanel extends JPanel { 48 | DesktopPane parent; 49 | public AbstractMapProvider chosenProvider; 50 | 51 | Map providerList = new TreeMap() { 52 | { 53 | put("Google Maps", new Google.GoogleMapProvider()); 54 | put("Google Terrain", new Google.GoogleTerrainProvider()); 55 | put("Google Maps Simple", new Google.GoogleSimplifiedProvider()); 56 | put("Microsoft Aerial", new Microsoft.AerialProvider()); 57 | // put("MapBox World Light", new MapBox.WorldLightProvider()); 58 | put("ESRI World Terrain", new EsriProvider.WorldTerrain()); 59 | put("ESRI NatGeo", new EsriProvider.NatGeoWorldMap()); 60 | put("ESRI Ocean Basemap", new EsriProvider.OceanBasemap()); 61 | put("ESRI World Gray Canvas", new EsriProvider.WorldGrayCanvas()); 62 | // put("ESRI World Physical", new EsriProvider.WorldPhysical()); 63 | put("ESRI World Shaded Relief", new EsriProvider.WorldShadedRelief()); 64 | put("ESRI World Topo", new EsriProvider.WorldTopoMap()); 65 | // put("Yahoo Aerial", new Yahoo.AerialProvider()); 66 | // put("MapQuest Aerial", new MapQuestProvider.Aerial()); 67 | } 68 | }; 69 | 70 | public BaseMapPanel(DesktopPane father) { 71 | parent = father; 72 | 73 | setLayout(new MigLayout("wrap 1")); 74 | ButtonGroup group = new ButtonGroup(); 75 | 76 | for (Entry entry : providerList.entrySet()) { 77 | String name = entry.getKey(); 78 | final AbstractMapProvider provider = entry.getValue(); 79 | JRadioButton button = new JRadioButton(name); 80 | add(button); 81 | 82 | group.add(button); 83 | button.addActionListener(new ActionListener() { 84 | public void actionPerformed(ActionEvent e) { 85 | chosenProvider = provider; 86 | if (parent.sketch != null) { 87 | parent.sketch.map.mapDisplay.setProvider(provider); 88 | if(parent.sketch.leftMap != null) parent.sketch.leftMap.mapDisplay.setProvider(provider); 89 | if(parent.sketch.rightMap != null) parent.sketch.rightMap.mapDisplay.setProvider(provider); 90 | } 91 | } 92 | }); 93 | if (name.equals("Microsoft Aerial")) { 94 | button.doClick(); 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/gui/CombinedControlPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package gui; 23 | 24 | import java.awt.Color; 25 | import java.awt.Font; 26 | import java.awt.event.MouseAdapter; 27 | import java.awt.event.MouseEvent; 28 | 29 | import javax.swing.JPanel; 30 | 31 | import main.DesktopPane; 32 | import net.miginfocom.swing.MigLayout; 33 | 34 | import javax.swing.JSeparator; 35 | import javax.swing.JLabel; 36 | 37 | public class CombinedControlPanel extends JPanel { 38 | 39 | /** 40 | * 41 | */ 42 | private static final long serialVersionUID = 1L; 43 | private DesktopPane parent; 44 | boolean line = true; 45 | boolean point = false; 46 | boolean vector = false; 47 | // boolean ghost = false; 48 | LinePanel linePanel; 49 | PointPanel pointPanel; 50 | VectorPanel vectorPanel; 51 | // GhostPanel ghostPanel; 52 | 53 | String formattedLabel(String str, boolean flag) { 54 | String downArrowLabel = "\u25BC "+str; 55 | String upArrowLabel = "\u25B2 "+str; 56 | return (flag?downArrowLabel:upArrowLabel); 57 | } 58 | 59 | public CombinedControlPanel(DesktopPane father) { 60 | parent = father; 61 | setLayout(new MigLayout("insets 10", "[145!]", "[]10[]10[]10[]10[]10[]10[]10[]10[]10[]10[]10[]10[]")); 62 | add(parent.controlPanel, "cell 0 0,growx"); 63 | 64 | linePanel = new LinePanel(parent); 65 | pointPanel = new PointPanel(parent); 66 | vectorPanel = new VectorPanel(parent); 67 | // ghostPanel = new GhostPanel(parent); 68 | 69 | JSeparator separator = new JSeparator(); 70 | add(separator, "cell 0 1,growx"); 71 | 72 | // Tracks -- Added Underlay(Ghost) here 73 | JLabel linelabel = new JLabel(formattedLabel("Tracks", line)); 74 | linelabel.setForeground(Color.BLACK); 75 | linelabel.setFont(new Font("Arial", Font.BOLD, 10)); 76 | linelabel.setBackground(Color.LIGHT_GRAY); 77 | add(linelabel, "cell 0 2"); 78 | linelabel.addMouseListener(new MouseAdapter() { 79 | @Override 80 | public void mousePressed(MouseEvent e) { 81 | if (line) { 82 | remove(linePanel); 83 | } else { 84 | add(linePanel, "cell 0 3,grow"); 85 | } 86 | revalidate(); 87 | parent.controlContainer.pack(); 88 | line = !line; 89 | ((JLabel) e.getSource()).setText(formattedLabel("Tracks", line)); 90 | } 91 | }); 92 | if (line){ 93 | add(linePanel, "cell 0 3,grow"); 94 | } 95 | 96 | JSeparator separator1 = new JSeparator(); 97 | add(separator1, "cell 0 4,growx"); 98 | 99 | JLabel pointlabel = new JLabel(formattedLabel("Points", point)); 100 | pointlabel.setForeground(Color.BLACK); 101 | pointlabel.setFont(new Font("Arial", Font.BOLD, 10)); 102 | pointlabel.setBackground(Color.LIGHT_GRAY); 103 | add(pointlabel, "cell 0 5"); 104 | pointlabel.addMouseListener(new MouseAdapter() { 105 | @Override 106 | public void mousePressed(MouseEvent e) { 107 | if (point) { 108 | remove(pointPanel); 109 | } else { 110 | add(pointPanel, "cell 0 6,grow"); 111 | } 112 | revalidate(); 113 | parent.controlContainer.pack(); 114 | point = !point; 115 | ((JLabel) e.getSource()).setText(formattedLabel("Points", point)); 116 | } 117 | }); 118 | 119 | JSeparator separator2 = new JSeparator(); 120 | add(separator2, "cell 0 7,growx"); 121 | 122 | JLabel vectorlabel = new JLabel(formattedLabel("Vectors", vector)); 123 | vectorlabel.setForeground(Color.BLACK); 124 | vectorlabel.setFont(new Font("Arial", Font.BOLD, 10)); 125 | vectorlabel.setBackground(Color.LIGHT_GRAY); 126 | add(vectorlabel, "cell 0 8"); 127 | vectorlabel.addMouseListener(new MouseAdapter() { 128 | @Override 129 | public void mousePressed(MouseEvent e) { 130 | if (vector) { 131 | remove(vectorPanel); 132 | } else { 133 | add(vectorPanel, "cell 0 9,grow"); 134 | } 135 | revalidate(); 136 | parent.controlContainer.pack(); 137 | vector = !vector; 138 | ((JLabel) e.getSource()).setText(formattedLabel("Vectors", vector)); 139 | } 140 | }); 141 | 142 | JSeparator separator3 = new JSeparator(); 143 | add(separator3, "cell 0 10,growx"); 144 | 145 | JLabel legendlabel = new JLabel(formattedLabel("Legend", parent.legend)); 146 | legendlabel.setForeground(Color.BLACK); 147 | legendlabel.setFont(new Font("Arial", Font.BOLD, 10)); 148 | legendlabel.setBackground(Color.LIGHT_GRAY); 149 | add(legendlabel, "cell 0 11"); 150 | legendlabel.addMouseListener(new MouseAdapter() { 151 | @Override 152 | public void mousePressed(MouseEvent e) { 153 | if (parent.legend) { 154 | remove(parent.legendPanel); 155 | } else { 156 | add(parent.legendPanel, "cell 0 12,grow"); 157 | } 158 | revalidate(); 159 | parent.controlContainer.pack(); 160 | parent.legend = !parent.legend; 161 | ((JLabel) e.getSource()).setText(formattedLabel("Legend", parent.legend)); 162 | } 163 | }); 164 | 165 | revalidate(); 166 | parent.controlContainer.pack(); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/gui/ControlPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package gui; 23 | 24 | import java.awt.Color; 25 | import java.awt.Font; 26 | import java.awt.Insets; 27 | import java.awt.event.ActionEvent; 28 | import java.awt.event.ActionListener; 29 | import java.awt.event.MouseAdapter; 30 | import java.awt.event.MouseEvent; 31 | 32 | import javax.swing.JButton; 33 | import javax.swing.JCheckBox; 34 | import javax.swing.JFileChooser; 35 | import javax.swing.JLabel; 36 | import javax.swing.JPanel; 37 | import javax.swing.JSlider; 38 | import javax.swing.JSpinner; 39 | import javax.swing.SpinnerNumberModel; 40 | import javax.swing.SwingConstants; 41 | import javax.swing.ToolTipManager; 42 | import javax.swing.UIManager; 43 | import javax.swing.event.ChangeEvent; 44 | import javax.swing.event.ChangeListener; 45 | 46 | import main.DesktopPane; 47 | import main.SketchData; 48 | import net.miginfocom.swing.MigLayout; 49 | 50 | import java.awt.Dimension; 51 | 52 | public class ControlPanel extends JPanel { 53 | /** 54 | * 55 | */ 56 | private static final long serialVersionUID = 1L; 57 | static int openFrameCount = 0; 58 | static final int xOffset = 30, yOffset = 30; 59 | 60 | public JSlider seek; 61 | public JFileChooser dataChooser; 62 | private DesktopPane parent; 63 | private SketchData data; 64 | 65 | public ControlPanel(DesktopPane father) { 66 | parent = father; 67 | data = parent.data; 68 | try { 69 | UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); 70 | } catch (Exception e) { 71 | e.printStackTrace(); 72 | } 73 | setLayout(new MigLayout("insets 0", "[20px:20px:20px][15.00][20px:20px:20px,fill][][grow,fill][]", 74 | "[][][][grow,fill][][grow,fill][][][]")); 75 | 76 | JSlider speed = new JSlider(); 77 | speed.setForeground(Color.BLACK); 78 | speed.setBackground(Color.LIGHT_GRAY); 79 | speed.setToolTipText("Speed"); 80 | speed.setPaintTicks(true); 81 | speed.setMajorTickSpacing(1); 82 | speed.setSnapToTicks(true); 83 | speed.setMinimum(0); 84 | speed.setMaximum(10); 85 | speed.setOrientation(SwingConstants.VERTICAL); 86 | speed.setInverted(false); 87 | this.add(speed, "cell 0 0 1 8,alignx center"); 88 | speed.addChangeListener(new ChangeListener() { 89 | public void stateChanged(ChangeEvent evt) { 90 | JSlider slider = (JSlider) evt.getSource(); 91 | int reverseValue = 1 + ((slider.getValue() - 10) * -1); // remap 10-1 to 1-10 92 | data.speed = reverseValue; 93 | } 94 | }); 95 | speed.setValue(7); 96 | 97 | seek = new JSlider(); 98 | seek.setForeground(Color.BLACK); 99 | seek.setBackground(Color.LIGHT_GRAY); 100 | seek.setToolTipText("Seek"); 101 | seek.setMajorTickSpacing(5); 102 | seek.setOrientation(SwingConstants.VERTICAL); 103 | seek.setValue(data.seek); 104 | seek.setMinimum(0); 105 | seek.setMaximum((data.totalTime / data.dataInterval)); 106 | this.add(seek, "cell 2 0 1 8,alignx center"); 107 | seek.addChangeListener(new ChangeListener() { 108 | public void stateChanged(ChangeEvent evt) { 109 | JSlider slider = (JSlider) evt.getSource(); 110 | if (data.timeUnit.equals("minutes")) { 111 | data.currentTime = data.startTime.plusMinutes(slider.getValue() * data.dataInterval); 112 | } else if (data.timeUnit.equals("seconds")) { 113 | data.currentTime = data.startTime.plusSeconds(slider.getValue() * data.dataInterval); 114 | } 115 | parent.timeLine.setMarker(data.currentTime); 116 | } 117 | }); 118 | seek.addMouseListener(new MouseAdapter() { 119 | @Override 120 | public void mousePressed(MouseEvent arg0) { 121 | data.mouse = true; 122 | } 123 | 124 | @Override 125 | public void mouseReleased(MouseEvent arg0) { 126 | data.mouse = false; 127 | } 128 | }); 129 | 130 | final JButton Pause = new JButton("Play"); 131 | Pause.setIconTextGap(0); 132 | Pause.setHorizontalTextPosition(SwingConstants.LEFT); 133 | Pause.setForeground(Color.BLACK); 134 | Pause.setBackground(new Color(227, 227, 227)); 135 | Pause.setFont(new Font("Arial", Font.PLAIN, 9)); 136 | Pause.setMargin(new Insets(0, 0, 0, 0)); 137 | Pause.setFont(new Font("Arial", Font.PLAIN, 9)); 138 | this.add(Pause, "cell 4 0 2 1,growx"); 139 | Pause.addActionListener(new ActionListener() { 140 | public void actionPerformed(ActionEvent evt) { 141 | JButton button = (JButton) evt.getSource(); 142 | data.pause = !data.pause; 143 | if (data.pause) { 144 | button.setText("Play"); 145 | } else { 146 | button.setText("Pause"); 147 | 148 | } 149 | } 150 | }); 151 | 152 | JButton Reset = new JButton("Stop"); 153 | Reset.setIconTextGap(0); 154 | Reset.setHorizontalTextPosition(SwingConstants.LEFT); 155 | Reset.setForeground(Color.BLACK); 156 | Reset.setBackground(new Color(227, 227, 227)); 157 | Reset.setFont(new Font("Arial", Font.PLAIN, 9)); 158 | Reset.setMargin(new Insets(0, 0, 0, 0)); 159 | this.add(Reset, "cell 4 1 2 1,growx"); 160 | Reset.addActionListener(new ActionListener() { 161 | public void actionPerformed(ActionEvent evt) { 162 | seek.setValue(0); 163 | data.pause = true; 164 | Pause.setText("Play"); 165 | } 166 | }); 167 | 168 | JCheckBox Loop = new JCheckBox("Loop"); 169 | Loop.setForeground(Color.BLACK); 170 | Loop.setBackground(Color.LIGHT_GRAY); 171 | Loop.setFont(new Font("Arial", Font.PLAIN, 9)); 172 | this.add(Loop, "cell 4 2 2 1,growx"); 173 | Loop.addActionListener(new ActionListener() { 174 | public void actionPerformed(ActionEvent evt) { 175 | JCheckBox cb = (JCheckBox) evt.getSource(); 176 | if (cb.isSelected()) { 177 | data.loop = true; 178 | } else { 179 | data.loop = false; 180 | } 181 | } 182 | }); 183 | 184 | JButton zoomIn = new JButton("+"); 185 | zoomIn.setMaximumSize(new Dimension(45, 26)); 186 | zoomIn.setIconTextGap(0); 187 | zoomIn.setHorizontalTextPosition(SwingConstants.LEFT); 188 | zoomIn.setForeground(Color.BLACK); 189 | zoomIn.setBackground(new Color(227, 227, 227)); 190 | zoomIn.setFont(new Font("Arial", Font.PLAIN, 9)); 191 | zoomIn.setMargin(new Insets(0, 0, 0, 0)); 192 | zoomIn.setFont(new Font("Arial", Font.PLAIN, 9)); 193 | this.add(zoomIn, "flowy,cell 4 4 2 1,alignx right"); 194 | zoomIn.addActionListener(new ActionListener() { 195 | public void actionPerformed(ActionEvent evt) { 196 | parent.sketch.zoomIn(); 197 | } 198 | }); 199 | 200 | JButton center = new JButton("Reset"); 201 | center.setMaximumSize(new Dimension(45, 26)); 202 | center.setIconTextGap(0); 203 | center.setHorizontalTextPosition(SwingConstants.LEFT); 204 | center.setForeground(Color.BLACK); 205 | center.setBackground(new Color(227, 227, 227)); 206 | center.setFont(new Font("Arial", Font.PLAIN, 9)); 207 | center.setMargin(new Insets(0, 0, 0, 0)); 208 | center.setFont(new Font("Arial", Font.PLAIN, 9)); 209 | this.add(center, "cell 4 4 2 1,alignx right"); 210 | center.addActionListener(new ActionListener() { 211 | public void actionPerformed(ActionEvent evt) { 212 | parent.sketch.zoomAndPan(data.locations); 213 | } 214 | }); 215 | 216 | JButton zoomOut = new JButton("-"); 217 | zoomOut.setMaximumSize(new Dimension(45, 26)); 218 | zoomOut.setIconTextGap(0); 219 | zoomOut.setHorizontalTextPosition(SwingConstants.LEFT); 220 | zoomOut.setForeground(Color.BLACK); 221 | zoomOut.setBackground(new Color(227, 227, 227)); 222 | zoomOut.setFont(new Font("Arial", Font.PLAIN, 9)); 223 | zoomOut.setMargin(new Insets(0, 0, 0, 0)); 224 | zoomOut.setFont(new Font("Arial", Font.PLAIN, 9)); 225 | this.add(zoomOut, "cell 4 4 2 1,alignx right"); 226 | zoomOut.addActionListener(new ActionListener() { 227 | public void actionPerformed(ActionEvent evt) { 228 | parent.sketch.zoomOut(); 229 | } 230 | }); 231 | 232 | JCheckBox Alpha = new JCheckBox("Fade Data"); 233 | Alpha.setForeground(Color.BLACK); 234 | Alpha.setBackground(Color.LIGHT_GRAY); 235 | Alpha.setFont(new Font("Arial", Font.PLAIN, 9)); 236 | Alpha.setToolTipText(""); 237 | ToolTipManager.sharedInstance().registerComponent(Alpha); 238 | this.add(Alpha, "cell 4 6 2 1,growx"); 239 | Alpha.addChangeListener(new ChangeListener() { 240 | public void stateChanged(ChangeEvent evt) { 241 | JCheckBox cb = (JCheckBox) evt.getSource(); 242 | if (cb.isSelected()) { 243 | data.falloff = true; 244 | } else { 245 | data.falloff = false; 246 | } 247 | } 248 | }); 249 | Alpha.setSelected(true); 250 | 251 | JSpinner AlphaValue = new JSpinner(); 252 | AlphaValue.setForeground(Color.BLACK); 253 | AlphaValue.setBackground(Color.LIGHT_GRAY); 254 | AlphaValue.setFont(new Font("Arial", Font.PLAIN, 9)); 255 | AlphaValue.setModel(new SpinnerNumberModel(data.alphaMaxHours, 1, data.alphaMaxHours * 100, 1)); 256 | AlphaValue.setToolTipText(""); 257 | ToolTipManager.sharedInstance().registerComponent(AlphaValue); 258 | this.add(AlphaValue, "flowx,cell 4 7 2 1,growx"); 259 | AlphaValue.addChangeListener(new ChangeListener() { 260 | public void stateChanged(ChangeEvent evt) { 261 | JSpinner spin = (JSpinner) evt.getSource(); 262 | data.alphaMaxHours = (Integer) spin.getValue(); 263 | } 264 | }); 265 | 266 | JLabel label = new JLabel("Speed"); 267 | label.setBackground(Color.LIGHT_GRAY); 268 | label.setForeground(Color.BLACK); 269 | label.setFont(new Font("Arial", Font.PLAIN, 8)); 270 | this.add(label, "cell 0 8"); 271 | 272 | JLabel lblSeek = new JLabel("Seek"); 273 | lblSeek.setBackground(Color.LIGHT_GRAY); 274 | lblSeek.setForeground(Color.BLACK); 275 | lblSeek.setFont(new Font("Arial", Font.PLAIN, 8)); 276 | this.add(lblSeek, "cell 2 8"); 277 | 278 | String unit; 279 | if (data.timeUnit.equals("minutes")) { 280 | unit = "(h)"; 281 | } else { 282 | unit = "(m)"; 283 | } 284 | JLabel lblPointLifehours = new JLabel("Fade Duration " + unit); 285 | lblPointLifehours.setHorizontalAlignment(SwingConstants.RIGHT); 286 | lblPointLifehours.setForeground(Color.BLACK); 287 | lblPointLifehours.setFont(new Font("Arial", Font.PLAIN, 8)); 288 | lblPointLifehours.setBackground(Color.LIGHT_GRAY); 289 | this.add(lblPointLifehours, "cell 4 8 2 1,alignx right"); 290 | 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /src/gui/GradientEditor.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package gui; 23 | 24 | import java.awt.Color; 25 | import java.awt.Dimension; 26 | import java.awt.Graphics; 27 | import java.awt.Graphics2D; 28 | import java.awt.Polygon; 29 | import java.awt.Rectangle; 30 | import java.awt.event.ActionEvent; 31 | import java.awt.event.ActionListener; 32 | import java.awt.event.MouseAdapter; 33 | import java.awt.event.MouseEvent; 34 | import java.awt.event.MouseMotionListener; 35 | import java.io.File; 36 | import java.io.FileInputStream; 37 | import java.io.FileOutputStream; 38 | import java.io.InputStream; 39 | import java.io.OutputStream; 40 | import java.text.DecimalFormat; 41 | import java.util.ArrayList; 42 | import java.util.Collections; 43 | import java.util.Comparator; 44 | import java.util.Vector; 45 | 46 | import javax.swing.DefaultComboBoxModel; 47 | import javax.swing.ImageIcon; 48 | import javax.swing.JButton; 49 | import javax.swing.JColorChooser; 50 | import javax.swing.JComboBox; 51 | import javax.swing.JComponent; 52 | import javax.swing.JDialog; 53 | import javax.swing.JFileChooser; 54 | import javax.swing.JLabel; 55 | import javax.swing.JPanel; 56 | import javax.swing.JTextField; 57 | import javax.swing.filechooser.FileNameExtensionFilter; 58 | 59 | import org.gicentre.utils.colour.ColourRule; 60 | import org.gicentre.utils.colour.ColourTable; 61 | 62 | import main.DesktopPane; 63 | import net.miginfocom.swing.MigLayout; 64 | 65 | @SuppressWarnings("serial") 66 | public class GradientEditor extends JPanel { 67 | 68 | public DesktopPane parent; 69 | private ArrayList list; 70 | private ControlPoint selected; 71 | private Polygon poly = new Polygon(); 72 | private Polygon square = new Polygon(); 73 | private JButton del = new JButton("Delete"); 74 | private int x; 75 | private int y; 76 | private int width; 77 | private int barHeight; 78 | public ColourTable currentSwatch; 79 | private ArrayList listeners = new ArrayList(); 80 | private JComboBox comboBox; 81 | private JButton okButton = new JButton("OK"); 82 | private JButton resetButton = new JButton("Reset"); 83 | private JButton loadButton = new JButton("Load File"); 84 | private JButton saveButton = new JButton("Save File"); 85 | private JButton newButton = new JButton("Add to List"); 86 | private JButton colButton = new JButton(""); 87 | private JTextField textField = new JTextField(); 88 | private JLabel colLabel = new JLabel("Color:"); 89 | private JLabel locLabel = new JLabel("Location:"); 90 | private JLabel label = new JLabel("%"); 91 | private JTextField nameField = new JTextField(); 92 | private JDialog mom; 93 | DecimalFormat df = new DecimalFormat("##.##"); 94 | 95 | LinePanel lp; 96 | PointPanel pp; 97 | VectorPanel vp; 98 | // BoundaryPanel bp; 99 | static int LINE = 1; 100 | static int POINT = 2; 101 | static int VECTOR = 3; 102 | static int BOUNDARY = 4; 103 | int owner; 104 | 105 | public GradientEditor(DesktopPane father, JDialog m, LinePanel l) { 106 | this(father, m, LINE); 107 | } 108 | 109 | public GradientEditor(DesktopPane father, JDialog m, PointPanel p) { 110 | this(father, m, POINT); 111 | } 112 | 113 | public GradientEditor(DesktopPane father, JDialog m, VectorPanel v) { 114 | this(father, m, VECTOR); 115 | } 116 | 117 | // public GradientEditor(DesktopPane father, JDialog m, BoundaryPanel b) { 118 | // this(father, m, BOUNDARY); 119 | // } 120 | 121 | public GradientEditor(DesktopPane father, JDialog m, int o) { 122 | 123 | owner = o; 124 | parent = father; 125 | mom = m; 126 | 127 | textField.setMaximumSize(new Dimension(50, 2147483647)); 128 | textField.setColumns(10); 129 | 130 | comboBox = new JComboBox(parent.colors.largeRampList.toArray()); 131 | 132 | setLayout(new MigLayout("", "[grow][grow][fill]", "[][][][][][grow][]")); 133 | 134 | Gradient gradient = new Gradient(); 135 | gradient.setMinimumSize(new Dimension(400, 65)); 136 | add(gradient, "cell 0 5 3 1,growx"); 137 | 138 | comboBox.addActionListener(new ActionListener() { 139 | public void actionPerformed(ActionEvent e) { 140 | JComboBox comboBox = (JComboBox) e.getSource(); 141 | convertSwatch(parent.colors.coloursCont.get(comboBox.getSelectedIndex())); 142 | } 143 | }); 144 | 145 | setSelected(); 146 | 147 | // add(lblName, "flowx,cell 0 4 2 1,alignx trailing"); 148 | nameField.setColumns(10); 149 | 150 | // add(nameField, "cell 0 4 2 1,growx"); 151 | 152 | add(newButton, "cell 2 4,growx"); 153 | newButton.addActionListener(new ActionListener() { 154 | public void actionPerformed(ActionEvent e) { 155 | ImageIcon largeSwatch = parent.colors.createSwatch(currentSwatch, "large"); 156 | ImageIcon smallSwatch = parent.colors.createSwatch(currentSwatch, "small"); 157 | parent.colors.coloursCont.add(currentSwatch); 158 | parent.colors.colorRampList.add(smallSwatch); 159 | parent.cp.linePanel.colorRampList.addItem(smallSwatch); 160 | parent.cp.pointPanel.colorRampList.addItem(smallSwatch); 161 | parent.cp.vectorPanel.colorRampList.addItem(smallSwatch); 162 | parent.colors.largeRampList.add(largeSwatch); 163 | comboBox.addItem(largeSwatch); 164 | comboBox.setSelectedIndex(comboBox.getItemCount() - 1); 165 | } 166 | }); 167 | 168 | add(saveButton, "cell 2 3,growx"); 169 | saveButton.addActionListener(new ActionListener() { 170 | public void actionPerformed(ActionEvent e) { 171 | JFileChooser chooser = new JFileChooser(); 172 | chooser.setCurrentDirectory(new File("./config/color")); 173 | chooser.setAcceptAllFileFilterUsed(false); 174 | FileNameExtensionFilter filter = new FileNameExtensionFilter("ColourTable File", "ctb", "CTB"); 175 | chooser.addChoosableFileFilter(filter); 176 | int retrival = chooser.showSaveDialog(null); 177 | if (retrival == JFileChooser.APPROVE_OPTION) { 178 | try { 179 | String string = chooser.getSelectedFile().getAbsolutePath(); 180 | if (!string.endsWith(".ctb")) { 181 | string = string + ".ctb"; 182 | } 183 | OutputStream out = new FileOutputStream(string); 184 | ColourTable.writeFile(currentSwatch, out); 185 | System.out.println("Saved Color Table: " + string); 186 | } catch (Exception ex) { 187 | ex.printStackTrace(); 188 | } 189 | } 190 | } 191 | }); 192 | 193 | add(loadButton, "cell 2 2,growx"); 194 | loadButton.addActionListener(new ActionListener() { 195 | public void actionPerformed(ActionEvent e) { 196 | JFileChooser chooser = new JFileChooser(); 197 | chooser.setCurrentDirectory(new File("./config/color")); 198 | chooser.setAcceptAllFileFilterUsed(false); 199 | FileNameExtensionFilter filter = new FileNameExtensionFilter("ColourTable File", "ctb", "CTB"); 200 | chooser.addChoosableFileFilter(filter); 201 | int retrival = chooser.showOpenDialog(null); 202 | if (retrival == JFileChooser.APPROVE_OPTION) { 203 | try { 204 | InputStream in = new FileInputStream(chooser.getSelectedFile()); 205 | convertSwatch(ColourTable.readFile(in)); 206 | newButton.doClick(); 207 | System.out.println("Loaded Color Table: " + chooser.getSelectedFile()); 208 | } catch (Exception ex) { 209 | ex.printStackTrace(); 210 | } 211 | } 212 | } 213 | }); 214 | 215 | add(resetButton, "cell 2 1,growx"); 216 | resetButton.addActionListener(new ActionListener() { 217 | public void actionPerformed(ActionEvent e) { 218 | convertSwatch(parent.colors.coloursCont.get(comboBox.getSelectedIndex())); 219 | } 220 | }); 221 | 222 | add(okButton, "cell 2 0,growx"); 223 | okButton.addActionListener(new ActionListener() { 224 | public void actionPerformed(ActionEvent e) { 225 | if (owner == LINE) 226 | parent.cp.linePanel.colorRampList.setSelectedIndex(comboBox.getSelectedIndex()); 227 | if (owner == POINT) 228 | parent.cp.pointPanel.colorRampList.setSelectedIndex(comboBox.getSelectedIndex()); 229 | if (owner == VECTOR) 230 | parent.cp.vectorPanel.colorRampList.setSelectedIndex(comboBox.getSelectedIndex()); 231 | mom.setVisible(false); 232 | } 233 | }); 234 | 235 | add(comboBox, "cell 0 0 2 1,growx"); 236 | 237 | add(colLabel, "flowx,cell 0 6,alignx center"); 238 | colButton.setMinimumSize(new Dimension(50, 20)); 239 | 240 | add(colButton, "cell 0 6,alignx center"); 241 | colButton.addActionListener(new ActionListener() { 242 | public void actionPerformed(ActionEvent e) { 243 | editPoint(); 244 | } 245 | }); 246 | add(locLabel, "flowx,cell 1 6"); 247 | 248 | add(textField, "cell 1 6"); 249 | 250 | add(label, "cell 1 6"); 251 | add(del, "cell 2 6,growx"); 252 | del.addActionListener(new ActionListener() { 253 | public void actionPerformed(ActionEvent e) { 254 | delPoint(); 255 | } 256 | }); 257 | 258 | poly.addPoint(0, 0); 259 | poly.addPoint(5, 5); 260 | poly.addPoint(-5, 5); 261 | 262 | square.addPoint(-5, 5); 263 | square.addPoint(5, 5); 264 | square.addPoint(5, 15); 265 | square.addPoint(-5, 15); 266 | 267 | gradient.addMouseListener(new MouseAdapter() { 268 | public void mousePressed(MouseEvent e) { 269 | selectPoint(e.getX(), e.getY()); 270 | repaint(0); 271 | 272 | if (e.getClickCount() == 2) { 273 | editPoint(); 274 | } 275 | } 276 | }); 277 | 278 | gradient.addMouseMotionListener(new MouseMotionListener() { 279 | public void mouseDragged(MouseEvent e) { 280 | movePoint(e.getX(), e.getY()); 281 | repaint(0); 282 | } 283 | 284 | public void mouseMoved(MouseEvent e) { 285 | } 286 | }); 287 | } 288 | 289 | public void reBuildList() { 290 | comboBox.setModel(new DefaultComboBoxModel(parent.colors.largeRampList.toArray())); 291 | } 292 | 293 | public void setSelected() { 294 | if (owner == LINE) 295 | comboBox.setSelectedIndex(parent.data.selectedLineSwatch); 296 | if (owner == POINT) 297 | comboBox.setSelectedIndex(parent.data.selectedPointSwatch); 298 | if (owner == VECTOR) 299 | comboBox.setSelectedIndex(parent.data.selectedVectorSwatch); 300 | if (owner == BOUNDARY) 301 | comboBox.setSelectedIndex(parent.data.selectedVectorSwatch); 302 | } 303 | 304 | private void convertSwatch(ColourTable colourTable) { 305 | list = new ArrayList(); 306 | currentSwatch = colourTable; 307 | Vector rules = currentSwatch.getColourRules(); 308 | for (int i = 1; i < rules.size(); i++) { 309 | ColourRule rule = rules.get(i); 310 | String string = Integer.toHexString(rule.getlColour()); 311 | string = string.substring(2, string.length()); 312 | Color color = Color.decode("#" + string); 313 | list.add(new ControlPoint(color, rule.getlIndex())); 314 | } 315 | repaint(); 316 | } 317 | 318 | public void addActionListener(ActionListener listener) { 319 | listeners.add(listener); 320 | } 321 | 322 | public void removeActionListener(ActionListener listener) { 323 | listeners.remove(listener); 324 | } 325 | 326 | private void fireUpdate() { 327 | currentSwatch = new ColourTable(); 328 | for (int i = 0; i < list.size(); i++) { 329 | ControlPoint now = (ControlPoint) list.get(i); 330 | currentSwatch.addContinuousColourRule(now.pos, now.col.getRGB()); 331 | } 332 | repaint(); 333 | ActionEvent event = new ActionEvent(this, 0, ""); 334 | for (int i = 0; i < listeners.size(); i++) { 335 | ((ActionListener) listeners.get(i)).actionPerformed(event); 336 | } 337 | } 338 | 339 | private boolean checkPoint(int mx, int my, ControlPoint pt) { 340 | int dx = (int) Math.abs((10 + (width * pt.pos)) - mx); 341 | int dy = Math.abs((y + barHeight + 7) - my); 342 | 343 | if ((dx < 5) && (dy < 7)) { 344 | return true; 345 | } 346 | 347 | return false; 348 | } 349 | 350 | private void addPoint() { 351 | ControlPoint point = new ControlPoint(colButton.getBackground(), 0.5f); 352 | for (int i = 0; i < list.size() - 1; i++) { 353 | ControlPoint now = (ControlPoint) list.get(i); 354 | ControlPoint next = (ControlPoint) list.get(i + 1); 355 | if ((now.pos <= 0.5f) && (next.pos >= 0.5f)) { 356 | list.add(i + 1, point); 357 | break; 358 | } 359 | 360 | } 361 | selected = point; 362 | sortPoints(); 363 | repaint(0); 364 | 365 | fireUpdate(); 366 | } 367 | 368 | private void sortPoints() { 369 | final ControlPoint firstPt = (ControlPoint) list.get(0); 370 | final ControlPoint lastPt = (ControlPoint) list.get(list.size() - 1); 371 | Comparator compare = new Comparator() { 372 | public int compare(Object first, Object second) { 373 | if (first == firstPt) { 374 | return -1; 375 | } 376 | if (second == lastPt) { 377 | return -1; 378 | } 379 | 380 | float a = ((ControlPoint) first).pos; 381 | float b = ((ControlPoint) second).pos; 382 | return (int) ((a - b) * 10000); 383 | } 384 | }; 385 | Collections.sort(list, compare); 386 | } 387 | 388 | private void editPoint() { 389 | if (selected == null) { 390 | Color color = null; 391 | Color col = JColorChooser.showDialog(this, "Select Color", color); 392 | if (col != null) { 393 | colButton.setBackground(col); 394 | } 395 | return; 396 | } 397 | Color col = JColorChooser.showDialog(this, "Select Color", selected.col); 398 | if (col != null) { 399 | selected.col = col; 400 | colButton.setBackground(col); 401 | repaint(0); 402 | fireUpdate(); 403 | } 404 | } 405 | 406 | private void selectPoint(int mx, int my) { 407 | if (!isEnabled()) { 408 | return; 409 | } 410 | 411 | for (int i = 1; i < list.size() - 1; i++) { 412 | if (checkPoint(mx, my, (ControlPoint) list.get(i))) { 413 | selected = (ControlPoint) list.get(i); 414 | textField.setText(df.format(selected.pos * 100)); 415 | colButton.setBackground(selected.col); 416 | return; 417 | } 418 | } 419 | if (checkPoint(mx, my, (ControlPoint) list.get(0))) { 420 | selected = (ControlPoint) list.get(0); 421 | textField.setText(df.format(selected.pos * 100)); 422 | colButton.setBackground(selected.col); 423 | return; 424 | } 425 | if (checkPoint(mx, my, (ControlPoint) list.get(list.size() - 1))) { 426 | selected = (ControlPoint) list.get(list.size() - 1); 427 | textField.setText(df.format(selected.pos * 100)); 428 | colButton.setBackground(selected.col); 429 | return; 430 | } else { 431 | // click to add like ps 432 | addPoint(); 433 | movePoint(mx, my); 434 | return; 435 | } 436 | } 437 | 438 | private void delPoint() { 439 | if (!isEnabled()) { 440 | return; 441 | } 442 | 443 | if (selected == null) { 444 | return; 445 | } 446 | if (list.indexOf(selected) == 0) { 447 | return; 448 | } 449 | if (list.indexOf(selected) == list.size() - 1) { 450 | return; 451 | } 452 | 453 | list.remove(selected); 454 | sortPoints(); 455 | repaint(0); 456 | fireUpdate(); 457 | } 458 | 459 | private void movePoint(int mx, int my) { 460 | if (!isEnabled()) { 461 | return; 462 | } 463 | 464 | // drag down to delete like ps 465 | if (my > 75) { 466 | delPoint(); 467 | return; 468 | } 469 | 470 | if (selected == null) { 471 | return; 472 | } 473 | if (list.indexOf(selected) == 0) { 474 | return; 475 | } 476 | if (list.indexOf(selected) == list.size() - 1) { 477 | return; 478 | } 479 | 480 | float newPos = (mx - 10) / (float) width; 481 | newPos = Math.min(1, newPos); 482 | newPos = Math.max(0, newPos); 483 | 484 | selected.pos = newPos; 485 | textField.setText(df.format(selected.pos * 100)); 486 | sortPoints(); 487 | fireUpdate(); 488 | } 489 | 490 | public class Gradient extends JComponent { 491 | 492 | @Override 493 | public void paintComponent(Graphics g1d) { 494 | 495 | Graphics2D g = (Graphics2D) g1d; 496 | width = getWidth() - 20; 497 | x = 10; 498 | y = 20; 499 | barHeight = 27; 500 | for (int s = 0; s < width; s++) { 501 | Rectangle rect = new Rectangle(s + x, y, 1, barHeight); 502 | String string = Integer.toHexString(currentSwatch.findColour((float) s / (width))); 503 | string = string.substring(2, string.length()); 504 | Color color = Color.decode("#" + string); 505 | g.setPaint(color); 506 | g.fill(rect); 507 | } 508 | 509 | g.setColor(Color.black); 510 | g.drawRect(10, y, width, barHeight - 1); 511 | 512 | for (int i = 0; i < list.size(); i++) { 513 | ControlPoint pt = (ControlPoint) list.get(i); 514 | g.translate(10 + (width * pt.pos), y + barHeight); 515 | 516 | if (pt == selected) { 517 | // g.drawLine(-5, 12, 5, 12); 518 | g.setColor(Color.DARK_GRAY); 519 | g.fillPolygon(poly); 520 | } 521 | g.setColor(pt.col); 522 | g.fillPolygon(square); 523 | g.setColor(Color.black); 524 | g.drawPolygon(square); 525 | g.drawPolygon(poly); 526 | 527 | g.translate(-10 - (width * pt.pos), -y - barHeight); 528 | } 529 | } 530 | } 531 | 532 | public void addPoint(float pos, Color col) { 533 | ControlPoint point = new ControlPoint(col, pos); 534 | for (int i = 0; i < list.size() - 1; i++) { 535 | ControlPoint now = (ControlPoint) list.get(i); 536 | ControlPoint next = (ControlPoint) list.get(i + 1); 537 | if ((now.pos <= 0.5f) && (next.pos >= 0.5f)) { 538 | list.add(i + 1, point); 539 | break; 540 | } 541 | } 542 | repaint(0); 543 | } 544 | 545 | public void setStart(Color col) { 546 | ((ControlPoint) list.get(0)).col = col; 547 | repaint(0); 548 | } 549 | 550 | public void setEnd(Color col) { 551 | ((ControlPoint) list.get(list.size() - 1)).col = col; 552 | repaint(0); 553 | } 554 | 555 | public void clearPoints() { 556 | for (int i = 1; i < list.size() - 1; i++) { 557 | list.remove(1); 558 | } 559 | 560 | repaint(0); 561 | fireUpdate(); 562 | } 563 | 564 | public int getControlPointCount() { 565 | return list.size(); 566 | } 567 | 568 | public float getPointPos(int index) { 569 | return ((ControlPoint) list.get(index)).pos; 570 | } 571 | 572 | public Color getColor(int index) { 573 | return ((ControlPoint) list.get(index)).col; 574 | } 575 | 576 | public class ControlPoint { 577 | 578 | public Color col; 579 | public float pos; 580 | 581 | private ControlPoint(Color col, float pos) { 582 | this.col = col; 583 | this.pos = pos; 584 | } 585 | } 586 | 587 | } 588 | -------------------------------------------------------------------------------- /src/gui/LegendPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | package gui; 22 | 23 | import javax.swing.JPanel; 24 | 25 | import main.DesktopPane; 26 | import main.SketchData; 27 | 28 | import net.miginfocom.swing.MigLayout; 29 | 30 | import javax.swing.JColorChooser; 31 | import javax.swing.JDialog; 32 | import javax.swing.JFileChooser; 33 | import javax.swing.JLabel; 34 | import javax.swing.JComboBox; 35 | import javax.swing.SwingConstants; 36 | import javax.swing.UIManager; 37 | 38 | import java.awt.Color; 39 | import java.awt.Component; 40 | import java.awt.Dimension; 41 | import java.awt.Font; 42 | import java.awt.Insets; 43 | import java.awt.event.ActionEvent; 44 | import java.awt.event.ActionListener; 45 | 46 | import javax.swing.JButton; 47 | import javax.swing.filechooser.FileNameExtensionFilter; 48 | 49 | import java.io.File; 50 | import java.io.FileInputStream; 51 | import java.io.FileOutputStream; 52 | import java.io.InputStream; 53 | import java.io.OutputStream; 54 | 55 | public class LegendPanel extends JPanel { 56 | 57 | /** 58 | * 59 | */ 60 | private static final long serialVersionUID = 1L; 61 | 62 | DesktopPane parent; 63 | SketchData data; 64 | 65 | WideComboBox fontChooser; 66 | JComboBox size; 67 | 68 | public LegendPanel(DesktopPane father) { 69 | parent = father; 70 | data = parent.data; 71 | 72 | setLayout(new MigLayout("insets 0", "[50%][][][grow]", "[][][][][][]")); 73 | 74 | JLabel lblFont = new JLabel("Font"); 75 | lblFont.setForeground(Color.BLACK); 76 | lblFont.setFont(new Font("Arial", Font.PLAIN, 8)); 77 | lblFont.setBackground(Color.LIGHT_GRAY); 78 | this.add(lblFont, "cell 0 0"); 79 | 80 | fontChooser = new WideComboBox(parent.fonts); 81 | // fontChooser.setEditable(true); 82 | fontChooser.setMaximumSize(new Dimension(80, 200)); 83 | fontChooser.setForeground(Color.BLACK); 84 | fontChooser.setBackground(UIManager.getColor("CheckBox.background")); 85 | fontChooser.setFont(new Font("Arial", Font.PLAIN, 9)); 86 | this.add(fontChooser, "cell 0 1 2 1,grow"); 87 | fontChooser.setSelectedItem("Arial"); 88 | fontChooser.addActionListener(new ActionListener() { 89 | public void actionPerformed(ActionEvent e) { 90 | WideComboBox temp = (WideComboBox) e.getSource(); 91 | String name = (String) temp.getSelectedItem(); 92 | if (name != null) { 93 | parent.sketch.legend.setFont(name, (Integer) size.getSelectedItem()); 94 | } 95 | } 96 | }); 97 | 98 | size = new JComboBox(); 99 | size.setForeground(Color.BLACK); 100 | size.setBackground(UIManager.getColor("CheckBox.background")); 101 | size.setFont(new Font("Arial", Font.PLAIN, 9)); 102 | this.add(size, "cell 2 1,growx"); 103 | for (int i = 8; i <= 18; i++) { 104 | size.addItem(i); 105 | } 106 | size.setSelectedIndex(2); 107 | size.addActionListener(new ActionListener() { 108 | public void actionPerformed(ActionEvent e) { 109 | JComboBox temp = (JComboBox) e.getSource(); 110 | int size = (Integer) temp.getSelectedItem(); 111 | parent.sketch.legend.setFont((String) fontChooser.getSelectedItem(), size); 112 | } 113 | }); 114 | 115 | JButton btnNewButton = new JButton("Unlock"); 116 | btnNewButton.setIconTextGap(0); 117 | btnNewButton.setHorizontalTextPosition(SwingConstants.LEFT); 118 | btnNewButton.setForeground(Color.BLACK); 119 | btnNewButton.setBackground(new Color(227, 227, 227)); 120 | btnNewButton.setFont(new Font("Arial", Font.PLAIN, 9)); 121 | btnNewButton.setMargin(new Insets(0, 0, 0, 0)); 122 | btnNewButton.setFont(new Font("Arial", Font.PLAIN, 9)); 123 | btnNewButton.addActionListener(new ActionListener() { 124 | public void actionPerformed(ActionEvent evt) { 125 | JButton button = (JButton) evt.getSource(); 126 | data.legendLocked = !data.legendLocked; 127 | if (data.legendLocked) { 128 | button.setText("Unlock"); 129 | parent.sketch.register(); 130 | } else { 131 | button.setText("Lock"); 132 | parent.sketch.unregister(); 133 | } 134 | } 135 | }); 136 | 137 | final JButton btnNewButton_1 = new JButton(""); 138 | add(btnNewButton_1, "cell 3 1,grow"); 139 | // btnNewButton_1.setMinimumSize(new Dimension(15,15)); 140 | btnNewButton_1.setBackground(parent.colors.getLegendColor()); 141 | btnNewButton_1.setMargin(new Insets(0, 0, 0, 0)); 142 | btnNewButton_1.addActionListener(new ActionListener() { 143 | public void actionPerformed(ActionEvent evt) { 144 | final JColorChooser colorChooser = new JColorChooser(); 145 | JDialog maxDialog = JColorChooser.createDialog((Component) evt.getSource(), "Pick a Color", true, // modal 146 | colorChooser, new ActionListener() { 147 | 148 | @Override 149 | public void actionPerformed(ActionEvent e) { 150 | parent.colors.setLegendColor(colorChooser.getColor()); 151 | btnNewButton_1.setBackground(parent.colors.getLegendColor()); 152 | parent.sketch.legend.setFontColor(parent.colors.getLegendColor().getRGB()); 153 | 154 | } 155 | }, new ActionListener() { 156 | @Override 157 | public void actionPerformed(ActionEvent event) { 158 | } 159 | }); 160 | maxDialog.setVisible(true); 161 | } 162 | }); 163 | this.add(btnNewButton, "cell 0 3 4 1,growx"); 164 | 165 | JButton resetButton = new JButton("Reset"); 166 | resetButton.setIconTextGap(0); 167 | resetButton.setHorizontalTextPosition(SwingConstants.LEFT); 168 | resetButton.setForeground(Color.BLACK); 169 | resetButton.setBackground(new Color(227, 227, 227)); 170 | resetButton.setFont(new Font("Arial", Font.PLAIN, 9)); 171 | resetButton.setMargin(new Insets(0, 0, 0, 0)); 172 | resetButton.setFont(new Font("Arial", Font.PLAIN, 9)); 173 | resetButton.addActionListener(new ActionListener() { 174 | public void actionPerformed(ActionEvent evt) { 175 | parent.sketch.resetLegend(); 176 | fontChooser.setSelectedItem("Arial"); 177 | size.setSelectedIndex(2); 178 | parent.colors.setLegendColor(Color.WHITE); 179 | btnNewButton_1.setBackground(parent.colors.getLegendColor()); 180 | parent.sketch.legend.setFontColor(parent.colors.getLegendColor().getRGB()); 181 | } 182 | }); 183 | this.add(resetButton, "cell 0 4 4 1,growx"); 184 | 185 | JButton btnSave = new JButton("Save"); 186 | btnSave.setMargin(new Insets(0, 0, 0, 0)); 187 | btnSave.setIconTextGap(0); 188 | btnSave.setHorizontalTextPosition(SwingConstants.LEFT); 189 | btnSave.setForeground(Color.BLACK); 190 | btnSave.setFont(new Font("Arial", Font.PLAIN, 9)); 191 | btnSave.setBackground(new Color(227, 227, 227)); 192 | add(btnSave, "cell 0 5,growx"); 193 | btnSave.addActionListener(new ActionListener() { 194 | public void actionPerformed(ActionEvent e) { 195 | JFileChooser chooser = new JFileChooser(); 196 | chooser.setCurrentDirectory(new File("./config/legend")); 197 | chooser.setAcceptAllFileFilterUsed(false); 198 | FileNameExtensionFilter filter = new FileNameExtensionFilter("Legend File", "xml", "XML"); 199 | chooser.addChoosableFileFilter(filter); 200 | int retrival = chooser.showSaveDialog(null); 201 | if (retrival == JFileChooser.APPROVE_OPTION) { 202 | try { 203 | String string = chooser.getSelectedFile().getAbsolutePath(); 204 | if (!string.endsWith(".xml")) { 205 | string = string + ".xml"; 206 | } 207 | OutputStream out = new FileOutputStream(string); 208 | parent.sketch.legend.writeFile(out); 209 | System.out.println("Saved Legend Layout: " + string); 210 | } catch (Exception ex) { 211 | ex.printStackTrace(); 212 | } 213 | } 214 | } 215 | }); 216 | 217 | JButton btnLoad = new JButton("Load"); 218 | btnLoad.setMargin(new Insets(0, 0, 0, 0)); 219 | btnLoad.setIconTextGap(0); 220 | btnLoad.setHorizontalTextPosition(SwingConstants.LEFT); 221 | btnLoad.setForeground(Color.BLACK); 222 | btnLoad.setFont(new Font("Arial", Font.PLAIN, 9)); 223 | btnLoad.setBackground(new Color(227, 227, 227)); 224 | add(btnLoad, "cell 1 5 3 1,growx"); 225 | btnLoad.addActionListener(new ActionListener() { 226 | public void actionPerformed(ActionEvent e) { 227 | JFileChooser chooser = new JFileChooser(); 228 | chooser.setCurrentDirectory(new File("./config/legend")); 229 | chooser.setAcceptAllFileFilterUsed(false); 230 | FileNameExtensionFilter filter = new FileNameExtensionFilter("Legend File", "xml", "XML"); 231 | chooser.addChoosableFileFilter(filter); 232 | int retrival = chooser.showOpenDialog(null); 233 | if (retrival == JFileChooser.APPROVE_OPTION) { 234 | try { 235 | InputStream in = new FileInputStream(chooser.getSelectedFile()); 236 | parent.sketch.legend.readFile(in); 237 | System.out.println("Loaded Legend Layout: " + chooser.getSelectedFile()); 238 | } catch (Exception ex) { 239 | ex.printStackTrace(); 240 | } 241 | } 242 | } 243 | }); 244 | 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /src/gui/LinePanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package gui; 23 | 24 | import javax.swing.JPanel; 25 | import javax.swing.JSpinner; 26 | import javax.swing.SpinnerNumberModel; 27 | 28 | import main.DesktopPane; 29 | import main.SketchData; 30 | import net.miginfocom.swing.MigLayout; 31 | 32 | import javax.swing.JButton; 33 | import javax.swing.JCheckBox; 34 | import javax.swing.JColorChooser; 35 | import javax.swing.JDialog; 36 | import javax.swing.JLabel; 37 | import javax.swing.SwingConstants; 38 | import javax.swing.ToolTipManager; 39 | import javax.swing.UIManager; 40 | 41 | import java.awt.Color; 42 | import java.awt.Component; 43 | import java.awt.Dimension; 44 | import java.awt.Font; 45 | import java.awt.Insets; 46 | import java.awt.event.ActionEvent; 47 | import java.awt.event.ActionListener; 48 | import java.util.ArrayList; 49 | 50 | import javax.swing.event.ChangeEvent; 51 | import javax.swing.event.ChangeListener; 52 | 53 | public class LinePanel extends JPanel { 54 | 55 | /** 56 | * 57 | */ 58 | private static final long serialVersionUID = 1L; 59 | 60 | DesktopPane parent; 61 | SketchData data; 62 | 63 | public WideComboBox strokeColor; 64 | public WideComboBox strokeWeight; 65 | public WideComboBox colorRampList; 66 | JDialog geCtr; 67 | LinePanel me; 68 | GradientEditor ge; 69 | 70 | public LinePanel(DesktopPane father) { 71 | parent = father; 72 | data = parent.data; 73 | me = this; 74 | setLayout(new MigLayout("insets 0", "[grow][grow][][]", "[][][][][][][][][][]")); 75 | 76 | JLabel lblLineColor = new JLabel("Line Color"); 77 | lblLineColor.setForeground(Color.BLACK); 78 | lblLineColor.setFont(new Font("Arial", Font.PLAIN, 8)); 79 | lblLineColor.setBackground(Color.LIGHT_GRAY); 80 | this.add(lblLineColor, "cell 0 0,alignx left,aligny baseline"); 81 | 82 | // 2 - color ramp list 83 | colorRampList = new WideComboBox(parent.colors.colorRampList.toArray()); 84 | colorRampList.setMaximumSize(new Dimension(120, 32767)); 85 | colorRampList.setMaximumRowCount(100); 86 | colorRampList.setForeground(Color.BLACK); 87 | colorRampList.setBackground(UIManager.getColor("CheckBox.background")); 88 | colorRampList.setFont(new Font("Arial", Font.PLAIN, 9)); 89 | this.add(colorRampList, "cell 0 2 3 1,growx"); 90 | colorRampList.addActionListener(new ActionListener() { 91 | public void actionPerformed(ActionEvent e) { 92 | WideComboBox comboBox = (WideComboBox) e.getSource(); 93 | parent.data.selectedLineSwatch = (int) comboBox.getSelectedIndex(); 94 | } 95 | }); 96 | 97 | // 1 - line color field name 98 | strokeColor = new WideComboBox(); 99 | strokeColor.setMaximumSize(new Dimension(120, 32767)); 100 | strokeColor.setMaximumRowCount(100); 101 | strokeColor.setForeground(Color.BLACK); 102 | strokeColor.setBackground(UIManager.getColor("CheckBox.background")); 103 | strokeColor.setFont(new Font("Arial", Font.PLAIN, 9)); 104 | this.add(strokeColor, "cell 0 1 3 1,growx"); 105 | strokeColor.addActionListener(new ActionListener() { 106 | public void actionPerformed(ActionEvent e) { 107 | WideComboBox cb = (WideComboBox) e.getSource(); 108 | String item = (String) cb.getSelectedItem(); 109 | 110 | if(item.equals("Identifier")) colorRampList.setEnabled(false); 111 | else colorRampList.setEnabled(true); 112 | 113 | data.strokeColorSelection = parent.attributes.getName(item); 114 | String unit = parent.attributes.getUnit(data.strokeColorSelection); 115 | if (unit.contains("none")) { 116 | unit = ""; 117 | } 118 | data.selectedColorUnit = unit; 119 | if (data.fieldColors.get(data.strokeColorSelection) != null) { 120 | // parent.colorPanel.colorRampList.setSelectedIndex(data.fieldColors.get(data.strokeColorSelection)); 121 | } 122 | } 123 | }); 124 | 125 | JCheckBox strokeColorToggle = new JCheckBox(""); 126 | strokeColorToggle.setForeground(Color.BLACK); 127 | strokeColorToggle.setFont(new Font("Arial", Font.PLAIN, 9)); 128 | strokeColorToggle.setBackground(Color.LIGHT_GRAY); 129 | this.add(strokeColorToggle, "cell 3 1,growx"); 130 | strokeColorToggle.addChangeListener(new ChangeListener() { 131 | public void stateChanged(ChangeEvent evt) { 132 | JCheckBox cb = (JCheckBox) evt.getSource(); 133 | if (cb.isSelected()) { 134 | data.strokeColorToggle = true; 135 | } else { 136 | data.strokeColorToggle = false; 137 | } 138 | } 139 | }); 140 | strokeColorToggle.setSelected(true); 141 | 142 | 143 | 144 | JButton editColor = new JButton("Edit"); 145 | editColor.setIconTextGap(0); 146 | editColor.setHorizontalTextPosition(SwingConstants.LEFT); 147 | editColor.setForeground(Color.BLACK); 148 | editColor.setBackground(new Color(227, 227, 227)); 149 | editColor.setFont(new Font("Arial", Font.PLAIN, 9)); 150 | editColor.setMargin(new Insets(0, 0, 0, 0)); 151 | this.add(editColor, "cell 3 2,grow"); 152 | editColor.addActionListener(new ActionListener() { 153 | public void actionPerformed(ActionEvent evt) { 154 | if (geCtr == null) { 155 | geCtr = new JDialog(parent); 156 | geCtr.setTitle("Gradient Editor"); 157 | geCtr.setLocationRelativeTo(parent); 158 | ge = new GradientEditor(parent, geCtr, me); 159 | geCtr.setContentPane(ge); 160 | geCtr.pack(); 161 | geCtr.setMinimumSize(geCtr.getSize()); 162 | } else { 163 | ge.reBuildList(); 164 | ge.setSelected(); 165 | } 166 | geCtr.setVisible(true); 167 | } 168 | }); 169 | 170 | JLabel lblLineWeight = new JLabel("Line Width"); 171 | lblLineWeight.setForeground(Color.BLACK); 172 | lblLineWeight.setFont(new Font("Arial", Font.PLAIN, 8)); 173 | lblLineWeight.setBackground(Color.LIGHT_GRAY); 174 | this.add(lblLineWeight, "cell 0 3,alignx left,aligny baseline"); 175 | 176 | strokeWeight = new WideComboBox(); 177 | strokeWeight.setMaximumSize(new Dimension(120, 32767)); 178 | strokeWeight.setMaximumRowCount(100); 179 | strokeWeight.setForeground(Color.BLACK); 180 | strokeWeight.setBackground(UIManager.getColor("CheckBox.background")); 181 | strokeWeight.setFont(new Font("Arial", Font.PLAIN, 9)); 182 | this.add(strokeWeight, "cell 0 4 3 1,growx"); 183 | strokeWeight.addActionListener(new ActionListener() { 184 | public void actionPerformed(ActionEvent e) { 185 | WideComboBox cb = (WideComboBox) e.getSource(); 186 | String item = (String) cb.getSelectedItem(); 187 | data.strokeWeightSelection = parent.attributes.getName(item); 188 | if (data.strokeWeightSelection != null) { 189 | String unit = parent.attributes.getUnit(data.strokeWeightSelection); 190 | if (unit.contains("none")) { 191 | unit = ""; 192 | } 193 | data.selectedStrokeWeightUnit = unit; 194 | } 195 | } 196 | }); 197 | 198 | JCheckBox strokeWeightToggle = new JCheckBox(""); 199 | strokeWeightToggle.setForeground(Color.BLACK); 200 | strokeWeightToggle.setBackground(Color.LIGHT_GRAY); 201 | strokeWeightToggle.setFont(new Font("Arial", Font.PLAIN, 9)); 202 | this.add(strokeWeightToggle, "cell 3 4,growx"); 203 | strokeWeightToggle.addChangeListener(new ChangeListener() { 204 | public void stateChanged(ChangeEvent evt) { 205 | JCheckBox cb = (JCheckBox) evt.getSource(); 206 | if (cb.isSelected()) { 207 | data.strokeWeightToggle = true; 208 | } else { 209 | data.strokeWeightToggle = false; 210 | } 211 | } 212 | }); 213 | strokeWeightToggle.setSelected(true); 214 | 215 | RangeSlider slider = new RangeSlider(); 216 | slider.setValue(1); 217 | slider.setUpperValue(10); 218 | slider.setMinimum(0); 219 | slider.setMaximum(20); 220 | slider.setMaximumSize(new Dimension(120, 32767)); 221 | this.add(slider, "cell 0 5 3 1,growx"); 222 | slider.addChangeListener(new ChangeListener() { 223 | public void stateChanged(ChangeEvent evt) { 224 | RangeSlider slider = (RangeSlider) evt.getSource(); 225 | data.strokeWeightMin = slider.getValue(); 226 | data.strokeWeightMax = slider.getUpperValue(); 227 | } 228 | }); 229 | 230 | ArrayList fields = parent.attributes.getSelectedFieldNames(); 231 | for (String string : fields) { 232 | strokeWeight.addItem(string); 233 | strokeColor.addItem(string); 234 | } 235 | 236 | strokeWeight.removeItem(parent.attributes.getIndexAlias()); 237 | 238 | if (data.strokeWeightSelection == null) { 239 | strokeWeight.setEnabled(false); 240 | strokeWeightToggle.setSelected(false); 241 | strokeWeightToggle.setEnabled(false); 242 | } 243 | 244 | 245 | // UNDERLAY 246 | // =================== 247 | 248 | JSpinner ghostWeight = new JSpinner(); 249 | ghostWeight.setForeground(Color.BLACK); 250 | ghostWeight.setBackground(Color.LIGHT_GRAY); 251 | ghostWeight.setFont(new Font("Arial", Font.PLAIN, 9)); 252 | ghostWeight.setModel(new SpinnerNumberModel(1, 1, 100, 1)); 253 | ghostWeight.setToolTipText(""); 254 | ToolTipManager.sharedInstance().registerComponent(ghostWeight); 255 | ghostWeight.addChangeListener(new ChangeListener() { 256 | public void stateChanged(ChangeEvent evt) { 257 | JSpinner spin = (JSpinner) evt.getSource(); 258 | data.ghostWeight = (Integer) spin.getValue(); 259 | } 260 | }); 261 | 262 | // Underlay label 263 | JLabel lblUnderlaySubheader = new JLabel("Underlay"); 264 | lblUnderlaySubheader.setForeground(Color.BLACK); 265 | lblUnderlaySubheader.setFont(new Font("Arial", Font.BOLD, 9)); 266 | lblUnderlaySubheader.setBackground(Color.LIGHT_GRAY); 267 | this.add(lblUnderlaySubheader, "cell 0 7,alignx left,aligny baseline"); 268 | // 269 | 270 | JLabel lblLineThickness = new JLabel("Line Width"); 271 | lblLineThickness.setForeground(Color.BLACK); 272 | lblLineThickness.setFont(new Font("Arial", Font.PLAIN, 8)); 273 | lblLineThickness.setBackground(Color.LIGHT_GRAY); 274 | this.add(lblLineThickness, "cell 0 8,alignx left,aligny baseline"); 275 | 276 | JLabel lblOpac = new JLabel("Opacity (%)"); 277 | lblOpac.setForeground(Color.BLACK); 278 | lblOpac.setFont(new Font("Arial", Font.PLAIN, 8)); 279 | lblOpac.setBackground(Color.LIGHT_GRAY); 280 | this.add(lblOpac, "cell 1 8,alignx left,aligny baseline"); 281 | ghostWeight.setValue(2); 282 | this.add(ghostWeight, "flowx,cell 0 9"); 283 | 284 | JCheckBox check = new JCheckBox(""); 285 | check.setForeground(Color.BLACK); 286 | check.setBackground(Color.LIGHT_GRAY); 287 | check.setFont(new Font("Arial", Font.PLAIN, 9)); 288 | check.setToolTipText(""); 289 | ToolTipManager.sharedInstance().registerComponent(check); 290 | this.add(check, "cell 3 9,growx"); 291 | check.addChangeListener(new ChangeListener() { 292 | public void stateChanged(ChangeEvent evt) { 293 | JCheckBox cb = (JCheckBox) evt.getSource(); 294 | if (cb.isSelected()) { 295 | data.ghost = true; 296 | } else { 297 | data.ghost = false; 298 | } 299 | } 300 | }); 301 | 302 | final JButton colorButton = new JButton(""); 303 | add(colorButton, "cell 2 9,grow"); 304 | colorButton.setMinimumSize(new Dimension(15, 15)); 305 | colorButton.setMaximumSize(new Dimension(15, 15)); 306 | colorButton.setBackground(data.ghostColor); 307 | colorButton.setMargin(new Insets(0, 0, 0, 0)); 308 | colorButton.addActionListener(new ActionListener() { 309 | public void actionPerformed(ActionEvent evt) { 310 | final JColorChooser colorChooser = new JColorChooser(); 311 | JDialog maxDialog = JColorChooser.createDialog((Component) evt.getSource(), "Pick a Color", true, // modal 312 | colorChooser, new ActionListener() { 313 | 314 | @Override 315 | public void actionPerformed(ActionEvent e) { 316 | data.ghostColor = colorChooser.getColor(); 317 | colorButton.setBackground(data.ghostColor); 318 | } 319 | }, new ActionListener() { 320 | @Override 321 | public void actionPerformed(ActionEvent event) { 322 | } 323 | }); 324 | maxDialog.setVisible(true); 325 | } 326 | }); 327 | 328 | JSpinner AlphaValue = new JSpinner(); 329 | AlphaValue.setForeground(Color.BLACK); 330 | AlphaValue.setBackground(Color.LIGHT_GRAY); 331 | AlphaValue.setFont(new Font("Arial", Font.PLAIN, 9)); 332 | AlphaValue.setModel(new SpinnerNumberModel(1, 1, 100, 1)); 333 | AlphaValue.setToolTipText(""); 334 | ToolTipManager.sharedInstance().registerComponent(AlphaValue); 335 | AlphaValue.addChangeListener(new ChangeListener() { 336 | public void stateChanged(ChangeEvent evt) { 337 | JSpinner spin = (JSpinner) evt.getSource(); 338 | data.ghostAlpha = (Integer) spin.getValue() * 255 / 100; // scale back to [0-255] 339 | } 340 | }); 341 | AlphaValue.setValue(15); 342 | this.add(AlphaValue, "flowx,cell 1 9"); 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /src/gui/PointPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package gui; 23 | 24 | import javax.swing.JPanel; 25 | 26 | import main.DesktopPane; 27 | import main.SketchData; 28 | import net.miginfocom.swing.MigLayout; 29 | 30 | import javax.swing.JButton; 31 | import javax.swing.JCheckBox; 32 | import javax.swing.JDialog; 33 | import javax.swing.JLabel; 34 | import javax.swing.SwingConstants; 35 | import javax.swing.UIManager; 36 | 37 | import java.awt.Color; 38 | import java.awt.Dimension; 39 | import java.awt.Font; 40 | import java.awt.Insets; 41 | import java.awt.event.ActionEvent; 42 | import java.awt.event.ActionListener; 43 | import java.util.ArrayList; 44 | 45 | import javax.swing.event.ChangeEvent; 46 | import javax.swing.event.ChangeListener; 47 | 48 | public class PointPanel extends JPanel { 49 | 50 | /** 51 | * 52 | */ 53 | private static final long serialVersionUID = 1L; 54 | 55 | DesktopPane parent; 56 | SketchData data; 57 | 58 | public WideComboBox pointColor; 59 | public WideComboBox pointSize; 60 | public WideComboBox colorRampList; 61 | GradientEditor ge; 62 | JDialog geCtr; 63 | PointPanel me; 64 | 65 | public PointPanel(DesktopPane father) { 66 | parent = father; 67 | data = parent.data; 68 | me = this; 69 | 70 | setLayout(new MigLayout("insets 0", "[grow][]", "[][]")); 71 | 72 | JLabel lblPointColor = new JLabel("Point Color"); 73 | lblPointColor.setForeground(Color.BLACK); 74 | lblPointColor.setFont(new Font("Arial", Font.PLAIN, 8)); 75 | lblPointColor.setBackground(Color.LIGHT_GRAY); 76 | this.add(lblPointColor, "cell 0 0,alignx left,aligny baseline"); 77 | 78 | // 2 - color ramp list 79 | colorRampList = new WideComboBox(parent.colors.colorRampList.toArray()); 80 | colorRampList.setMaximumSize(new Dimension(120, 32767)); 81 | colorRampList.setMaximumRowCount(100); 82 | colorRampList.setForeground(Color.BLACK); 83 | colorRampList.setBackground(UIManager.getColor("CheckBox.background")); 84 | colorRampList.setFont(new Font("Arial", Font.PLAIN, 9)); 85 | this.add(colorRampList, "cell 0 2,growx"); 86 | colorRampList.addActionListener(new ActionListener() { 87 | public void actionPerformed(ActionEvent e) { 88 | WideComboBox comboBox = (WideComboBox) e.getSource(); 89 | parent.data.selectedPointSwatch = (int) comboBox.getSelectedIndex(); 90 | } 91 | }); 92 | 93 | // 1 - point color field name 94 | pointColor = new WideComboBox(); 95 | pointColor.setMaximumSize(new Dimension(120, 32767)); 96 | pointColor.setMaximumRowCount(100); 97 | pointColor.setForeground(Color.BLACK); 98 | pointColor.setBackground(UIManager.getColor("CheckBox.background")); 99 | pointColor.setFont(new Font("Arial", Font.PLAIN, 9)); 100 | this.add(pointColor, "cell 0 1,growx"); 101 | pointColor.addActionListener(new ActionListener() { 102 | public void actionPerformed(ActionEvent e) { 103 | WideComboBox cb = (WideComboBox) e.getSource(); 104 | String item = (String) cb.getSelectedItem(); 105 | 106 | if(item.equals("Identifier")) colorRampList.setEnabled(false); 107 | else colorRampList.setEnabled(true); 108 | 109 | data.pointColorSelection = parent.attributes.getName(item); 110 | } 111 | }); 112 | 113 | 114 | 115 | JButton editColor = new JButton("Edit"); 116 | editColor.setIconTextGap(0); 117 | editColor.setHorizontalTextPosition(SwingConstants.LEFT); 118 | editColor.setForeground(Color.BLACK); 119 | editColor.setBackground(new Color(227, 227, 227)); 120 | editColor.setFont(new Font("Arial", Font.PLAIN, 9)); 121 | editColor.setMargin(new Insets(0, 0, 0, 0)); 122 | this.add(editColor, "cell 1 2,grow"); 123 | editColor.addActionListener(new ActionListener() { 124 | public void actionPerformed(ActionEvent evt) { 125 | if (geCtr == null) { 126 | geCtr = new JDialog(parent); 127 | geCtr.setTitle("Gradient Editor"); 128 | geCtr.setLocationRelativeTo(parent); 129 | ge = new GradientEditor(parent, geCtr, me); 130 | geCtr.setContentPane(ge); 131 | geCtr.pack(); 132 | geCtr.setMinimumSize(geCtr.getSize()); 133 | } else { 134 | ge.reBuildList(); 135 | ge.setSelected(); 136 | } 137 | geCtr.setVisible(true); 138 | } 139 | }); 140 | 141 | JLabel lblPointSize = new JLabel("Point Size"); 142 | lblPointSize.setForeground(Color.BLACK); 143 | lblPointSize.setFont(new Font("Arial", Font.PLAIN, 8)); 144 | lblPointSize.setBackground(Color.LIGHT_GRAY); 145 | this.add(lblPointSize, "cell 0 3,alignx left,aligny baseline"); 146 | 147 | pointSize = new WideComboBox(); 148 | pointSize.setMaximumSize(new Dimension(120, 32767)); 149 | pointSize.setMaximumRowCount(100); 150 | pointSize.setForeground(Color.BLACK); 151 | pointSize.setBackground(UIManager.getColor("CheckBox.background")); 152 | pointSize.setFont(new Font("Arial", Font.PLAIN, 9)); 153 | this.add(pointSize, "cell 0 4,growx"); 154 | pointSize.addActionListener(new ActionListener() { 155 | public void actionPerformed(ActionEvent e) { 156 | WideComboBox cb = (WideComboBox) e.getSource(); 157 | String item = (String) cb.getSelectedItem(); 158 | data.pointSizeSelection = parent.attributes.getName(item); 159 | } 160 | }); 161 | 162 | JCheckBox pointColorToggle = new JCheckBox(""); 163 | pointColorToggle.setForeground(Color.BLACK); 164 | pointColorToggle.setBackground(Color.LIGHT_GRAY); 165 | pointColorToggle.setFont(new Font("Arial", Font.PLAIN, 9)); 166 | this.add(pointColorToggle, "cell 1 1,growx"); 167 | pointColorToggle.addChangeListener(new ChangeListener() { 168 | public void stateChanged(ChangeEvent evt) { 169 | JCheckBox cb = (JCheckBox) evt.getSource(); 170 | if (cb.isSelected()) { 171 | data.pointColorToggle = true; 172 | } else { 173 | data.pointColorToggle = false; 174 | } 175 | } 176 | }); 177 | pointColorToggle.setSelected(false); 178 | 179 | JCheckBox pointSizeToggle = new JCheckBox(""); 180 | pointSizeToggle.setForeground(Color.BLACK); 181 | pointSizeToggle.setBackground(Color.LIGHT_GRAY); 182 | pointSizeToggle.setFont(new Font("Arial", Font.PLAIN, 9)); 183 | this.add(pointSizeToggle, "cell 1 4,growx"); 184 | pointSizeToggle.addChangeListener(new ChangeListener() { 185 | public void stateChanged(ChangeEvent evt) { 186 | JCheckBox cb = (JCheckBox) evt.getSource(); 187 | if (cb.isSelected()) { 188 | data.pointSizeToggle = true; 189 | } else { 190 | data.pointSizeToggle = false; 191 | } 192 | } 193 | }); 194 | pointSizeToggle.setSelected(false); 195 | 196 | RangeSlider slider = new RangeSlider(); 197 | slider.setValue(1); 198 | slider.setUpperValue(10); 199 | slider.setMinimum(0); 200 | slider.setMaximum(30); 201 | slider.setMaximumSize(new Dimension(120, 32767)); 202 | this.add(slider, "cell 0 5 2 1,growx"); 203 | slider.addChangeListener(new ChangeListener() { 204 | public void stateChanged(ChangeEvent evt) { 205 | RangeSlider slider = (RangeSlider) evt.getSource(); 206 | data.pointSizeMin = slider.getValue(); 207 | data.pointSizeMax = slider.getUpperValue(); 208 | } 209 | }); 210 | 211 | ArrayList fields = parent.attributes.getSelectedFieldNames(); 212 | for (String s : fields) { 213 | pointColor.addItem(s); 214 | pointSize.addItem(s); 215 | } 216 | pointSize.removeItem(parent.attributes.getIndexAlias()); 217 | 218 | if (data.pointSizeSelection == null) { 219 | pointSize.setEnabled(false); 220 | pointSizeToggle.setSelected(false); 221 | pointSizeToggle.setEnabled(false); 222 | } 223 | 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/gui/RangeSlider.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package gui; 23 | 24 | import javax.swing.JSlider; 25 | 26 | /** 27 | * An extension of JSlider to select a range of values using two thumb controls. 28 | * The thumb controls are used to select the lower and upper value of a range 29 | * with predetermined minimum and maximum values. 30 | * 31 | *

32 | * Note that RangeSlider makes use of the default BoundedRangeModel, which 33 | * supports an inner range defined by a value and an extent. The upper value 34 | * returned by RangeSlider is simply the lower value plus the extent. 35 | *

36 | */ 37 | @SuppressWarnings("serial") 38 | public class RangeSlider extends JSlider { 39 | /** 40 | * Constructs a RangeSlider with default minimum and maximum values of 0 and 41 | * 100. 42 | */ 43 | public RangeSlider() { 44 | initSlider(); 45 | } 46 | 47 | /** 48 | * Constructs a RangeSlider with the specified default minimum and maximum 49 | * values. 50 | */ 51 | public RangeSlider(int min, int max) { 52 | super(min, max); 53 | initSlider(); 54 | } 55 | 56 | /** 57 | * Initializes the slider by setting default properties. 58 | */ 59 | private void initSlider() { 60 | setOrientation(HORIZONTAL); 61 | } 62 | 63 | /** 64 | * Overrides the superclass method to install the UI delegate to draw two 65 | * thumbs. 66 | */ 67 | @Override 68 | public void updateUI() { 69 | setUI(new RangeSliderUI(this)); 70 | // Update UI for slider labels. This must be called after updating the 71 | // UI of the slider. Refer to JSlider.updateUI(). 72 | updateLabelUIs(); 73 | } 74 | 75 | /** 76 | * Returns the lower value in the range. 77 | */ 78 | @Override 79 | public int getValue() { 80 | return super.getValue(); 81 | } 82 | 83 | /** 84 | * Sets the lower value in the range. 85 | */ 86 | @Override 87 | public void setValue(int value) { 88 | int oldValue = getValue(); 89 | if (oldValue == value) { 90 | return; 91 | } 92 | // Compute new value and extent to maintain upper value. 93 | int oldExtent = getExtent(); 94 | int newValue = Math.min(Math.max(getMinimum(), value), oldValue + oldExtent); 95 | int newExtent = oldExtent + oldValue - newValue; 96 | // Set new value and extent, and fire a single change event. 97 | getModel().setRangeProperties(newValue, newExtent, getMinimum(), getMaximum(), getValueIsAdjusting()); 98 | } 99 | 100 | /** 101 | * Returns the upper value in the range. 102 | */ 103 | public int getUpperValue() { 104 | return getValue() + getExtent(); 105 | } 106 | 107 | /** 108 | * Sets the upper value in the range. 109 | */ 110 | public void setUpperValue(int value) { 111 | // Compute new extent. 112 | int lowerValue = getValue(); 113 | int newExtent = Math.min(Math.max(0, value - lowerValue), getMaximum() - lowerValue); 114 | // Set extent to set upper value. 115 | setExtent(newExtent); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/gui/VectorPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | package gui; 22 | 23 | import javax.swing.JPanel; 24 | 25 | import main.DesktopPane; 26 | import main.SketchData; 27 | import utils.Field; 28 | import net.miginfocom.swing.MigLayout; 29 | 30 | import javax.swing.JButton; 31 | import javax.swing.JCheckBox; 32 | import javax.swing.JDialog; 33 | import javax.swing.JLabel; 34 | import javax.swing.SwingConstants; 35 | import javax.swing.UIManager; 36 | 37 | import java.awt.Color; 38 | import java.awt.Dimension; 39 | import java.awt.Font; 40 | import java.awt.Insets; 41 | import java.awt.event.ActionEvent; 42 | import java.awt.event.ActionListener; 43 | import java.util.ArrayList; 44 | 45 | import javax.swing.event.ChangeEvent; 46 | import javax.swing.event.ChangeListener; 47 | 48 | public class VectorPanel extends JPanel { 49 | 50 | /** 51 | * 52 | */ 53 | private static final long serialVersionUID = 1L; 54 | 55 | DesktopPane parent; 56 | SketchData data; 57 | 58 | public WideComboBox vectorLength; 59 | public WideComboBox headingField; 60 | public WideComboBox colorRampList; 61 | JCheckBox vectorCheck; 62 | GradientEditor ge; 63 | JDialog geCtr; 64 | VectorPanel me; 65 | 66 | public VectorPanel(DesktopPane father) { 67 | parent = father; 68 | data = parent.data; 69 | me = this; 70 | 71 | setLayout(new MigLayout("insets 0", "[grow][]", "[]")); 72 | 73 | JLabel lblDirection = new JLabel("Direction"); 74 | lblDirection.setForeground(Color.BLACK); 75 | lblDirection.setFont(new Font("Arial", Font.PLAIN, 8)); 76 | lblDirection.setBackground(Color.LIGHT_GRAY); 77 | this.add(lblDirection, "cell 0 0,alignx left,aligny baseline"); 78 | 79 | headingField = new WideComboBox(); 80 | headingField.setMaximumSize(new Dimension(120, 32767)); 81 | headingField.setMaximumRowCount(100); 82 | headingField.setForeground(Color.BLACK); 83 | headingField.setBackground(UIManager.getColor("CheckBox.background")); 84 | headingField.setFont(new Font("Arial", Font.PLAIN, 9)); 85 | 86 | this.add(headingField, "cell 0 1,growx"); 87 | 88 | headingField.addActionListener(new ActionListener() { 89 | public void actionPerformed(ActionEvent e) { 90 | WideComboBox cb = (WideComboBox) e.getSource(); 91 | String item = (String) cb.getSelectedItem(); 92 | data.headingFieldSelection = parent.attributes.getName(item); 93 | } 94 | }); 95 | 96 | vectorCheck = new JCheckBox(""); 97 | vectorCheck.setForeground(Color.BLACK); 98 | vectorCheck.setBackground(Color.LIGHT_GRAY); 99 | vectorCheck.setFont(new Font("Arial", Font.PLAIN, 9)); 100 | 101 | this.add(vectorCheck, "cell 1 1,growx"); 102 | 103 | vectorCheck.addChangeListener(new ChangeListener() { 104 | public void stateChanged(ChangeEvent evt) { 105 | JCheckBox cb = (JCheckBox) evt.getSource(); 106 | if (cb.isSelected()) { 107 | data.vectorToggle = true; 108 | } else { 109 | data.vectorToggle = false; 110 | } 111 | } 112 | }); 113 | vectorCheck.setSelected(false); 114 | 115 | JLabel lblColor = new JLabel("Vector Color"); 116 | lblColor.setForeground(Color.BLACK); 117 | lblColor.setFont(new Font("Arial", Font.PLAIN, 8)); 118 | lblColor.setBackground(Color.LIGHT_GRAY); 119 | this.add(lblColor, "cell 0 2,alignx left,aligny baseline"); 120 | 121 | // 2 - color ramp list 122 | colorRampList = new WideComboBox(parent.colors.colorRampList.toArray()); 123 | colorRampList.setMaximumSize(new Dimension(120, 32767)); 124 | colorRampList.setMaximumRowCount(100); 125 | colorRampList.setForeground(Color.BLACK); 126 | colorRampList.setBackground(UIManager.getColor("CheckBox.background")); 127 | colorRampList.setFont(new Font("Arial", Font.PLAIN, 9)); 128 | this.add(colorRampList, "cell 0 4,growx"); 129 | colorRampList.addActionListener(new ActionListener() { 130 | public void actionPerformed(ActionEvent e) { 131 | WideComboBox comboBox = (WideComboBox) e.getSource(); 132 | parent.data.selectedVectorSwatch = (int) comboBox.getSelectedIndex(); 133 | } 134 | }); 135 | 136 | // 1 - vector color field name 137 | WideComboBox vectorColor = new WideComboBox(); 138 | vectorColor.setMaximumSize(new Dimension(120, 32767)); 139 | vectorColor.setMaximumRowCount(100); 140 | vectorColor.setForeground(Color.BLACK); 141 | vectorColor.setBackground(UIManager.getColor("CheckBox.background")); 142 | vectorColor.setFont(new Font("Arial", Font.PLAIN, 9)); 143 | this.add(vectorColor, "cell 0 3,growx"); 144 | vectorColor.addActionListener(new ActionListener() { 145 | public void actionPerformed(ActionEvent e) { 146 | WideComboBox cb = (WideComboBox) e.getSource(); 147 | String item = (String) cb.getSelectedItem(); 148 | 149 | if(item.equals("Identifier")) colorRampList.setEnabled(false); 150 | else colorRampList.setEnabled(true); 151 | 152 | data.vectorColorSelection = parent.attributes.getName(item); 153 | } 154 | }); 155 | 156 | JCheckBox vectorColorCheck = new JCheckBox(""); 157 | vectorColorCheck.setForeground(Color.BLACK); 158 | vectorColorCheck.setBackground(Color.LIGHT_GRAY); 159 | vectorColorCheck.setFont(new Font("Arial", Font.PLAIN, 9)); 160 | 161 | this.add(vectorColorCheck, "cell 1 3,growx"); 162 | vectorColorCheck.addChangeListener(new ChangeListener() { 163 | public void stateChanged(ChangeEvent evt) { 164 | JCheckBox cb = (JCheckBox) evt.getSource(); 165 | if (cb.isSelected()) { 166 | data.vectorColorToggle = true; 167 | } else { 168 | data.vectorColorToggle = false; 169 | } 170 | } 171 | }); 172 | vectorColorCheck.setSelected(false); 173 | 174 | JButton editColor = new JButton("Edit"); 175 | editColor.setIconTextGap(0); 176 | editColor.setHorizontalTextPosition(SwingConstants.LEFT); 177 | editColor.setForeground(Color.BLACK); 178 | editColor.setBackground(new Color(227, 227, 227)); 179 | editColor.setFont(new Font("Arial", Font.PLAIN, 9)); 180 | editColor.setMargin(new Insets(0, 0, 0, 0)); 181 | this.add(editColor, "cell 1 4,grow"); 182 | editColor.addActionListener(new ActionListener() { 183 | public void actionPerformed(ActionEvent evt) { 184 | if (geCtr == null) { 185 | geCtr = new JDialog(parent); 186 | geCtr.setTitle("Gradient Editor"); 187 | geCtr.setLocationRelativeTo(parent); 188 | ge = new GradientEditor(parent, geCtr, me); 189 | geCtr.setContentPane(ge); 190 | geCtr.pack(); 191 | geCtr.setMinimumSize(geCtr.getSize()); 192 | } else { 193 | ge.reBuildList(); 194 | ge.setSelected(); 195 | } 196 | geCtr.setVisible(true); 197 | } 198 | }); 199 | 200 | JLabel lblLength = new JLabel("Vector Length"); 201 | lblLength.setForeground(Color.BLACK); 202 | lblLength.setFont(new Font("Arial", Font.PLAIN, 8)); 203 | lblLength.setBackground(Color.LIGHT_GRAY); 204 | this.add(lblLength, "cell 0 5,alignx left,aligny baseline"); 205 | 206 | vectorLength = new WideComboBox(); 207 | vectorLength.setMaximumSize(new Dimension(120, 32767)); 208 | vectorLength.setMaximumRowCount(100); 209 | vectorLength.setForeground(Color.BLACK); 210 | vectorLength.setBackground(UIManager.getColor("CheckBox.background")); 211 | vectorLength.setFont(new Font("Arial", Font.PLAIN, 9)); 212 | 213 | this.add(vectorLength, "cell 0 6,growx"); 214 | 215 | vectorLength.addActionListener(new ActionListener() { 216 | public void actionPerformed(ActionEvent e) { 217 | WideComboBox cb = (WideComboBox) e.getSource(); 218 | String item = (String) cb.getSelectedItem(); 219 | data.vectorFieldSelection = parent.attributes.getName(item); 220 | } 221 | }); 222 | 223 | JCheckBox vectorLengthCheck = new JCheckBox(""); 224 | vectorLengthCheck.setForeground(Color.BLACK); 225 | vectorLengthCheck.setBackground(Color.LIGHT_GRAY); 226 | vectorLengthCheck.setFont(new Font("Arial", Font.PLAIN, 9)); 227 | 228 | this.add(vectorLengthCheck, "cell 1 6,growx"); 229 | vectorLengthCheck.addChangeListener(new ChangeListener() { 230 | public void stateChanged(ChangeEvent evt) { 231 | JCheckBox cb = (JCheckBox) evt.getSource(); 232 | if (cb.isSelected()) { 233 | data.vectorLengthToggle = true; 234 | } else { 235 | data.vectorLengthToggle = false; 236 | } 237 | } 238 | }); 239 | vectorLengthCheck.setSelected(false); 240 | 241 | RangeSlider slider = new RangeSlider(); 242 | slider.setValue(5); 243 | slider.setUpperValue(20); 244 | slider.setMinimum(0); 245 | slider.setMaximum(50); 246 | slider.setMaximumSize(new Dimension(120, 32767)); 247 | this.add(slider, "cell 0 7 2 1,growx"); 248 | slider.addChangeListener(new ChangeListener() { 249 | public void stateChanged(ChangeEvent evt) { 250 | RangeSlider slider = (RangeSlider) evt.getSource(); 251 | data.vectorLengthMin = slider.getValue(); 252 | data.vectorLengthMax = slider.getUpperValue(); 253 | } 254 | }); 255 | 256 | ArrayList fields = parent.attributes.getSelectedFields(); 257 | for (Field field : fields) { 258 | String name = field.getAlias(); 259 | vectorColor.addItem(name); 260 | 261 | float min = field.getMin(); 262 | float max = field.getMax(); 263 | 264 | if (max - min >= 345f && max - min <= 375f) { 265 | headingField.addItem(name); 266 | } else { 267 | vectorLength.addItem(name); 268 | } 269 | } 270 | 271 | headingField.removeItem(parent.attributes.getIndexAlias()); 272 | vectorLength.removeItem(parent.attributes.getIndexAlias()); 273 | 274 | if (headingField.getItemCount() == 0) { 275 | vectorCheck.setEnabled(false); 276 | headingField.setEnabled(false); 277 | vectorLength.setEnabled(false); 278 | vectorLengthCheck.setEnabled(false); 279 | vectorColor.setEnabled(false); 280 | vectorColorCheck.setEnabled(false); 281 | } 282 | 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /src/gui/WideComboBox.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package gui; 23 | 24 | import java.awt.Dimension; 25 | import java.util.Vector; 26 | 27 | import javax.swing.ComboBoxModel; 28 | import javax.swing.JComboBox; 29 | 30 | //makes the popup wide enough for listed items 31 | @SuppressWarnings("serial") 32 | public class WideComboBox extends JComboBox { 33 | public WideComboBox() { 34 | } 35 | 36 | public WideComboBox(final Object items[]) { 37 | super(items); 38 | } 39 | 40 | @SuppressWarnings("rawtypes") 41 | public WideComboBox(Vector items) { 42 | super(items); 43 | } 44 | 45 | public WideComboBox(ComboBoxModel aModel) { 46 | super(aModel); 47 | } 48 | 49 | private boolean layingOut = false; 50 | 51 | public void doLayout() { 52 | try { 53 | layingOut = true; 54 | super.doLayout(); 55 | } finally { 56 | layingOut = false; 57 | } 58 | } 59 | 60 | public Dimension getSize() { 61 | Dimension dim = super.getSize(); 62 | if (!layingOut) 63 | dim.width = Math.max(dim.width, getPreferredSize().width); 64 | return dim; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/Colors.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package main; 23 | 24 | import java.awt.Color; 25 | import java.awt.Graphics2D; 26 | import java.awt.Rectangle; 27 | import java.awt.image.BufferedImage; 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | import javax.swing.ImageIcon; 32 | 33 | import org.gicentre.utils.colour.ColourTable; 34 | 35 | public class Colors { 36 | 37 | // swatch dimensions, small for control panel, large for gradient editor 38 | public static final int LARGE_WIDTH = 300; 39 | public static final int LARGE_HEIGHT = 20; 40 | public static final int SMALL_WIDTH = 95; 41 | public static final int SMALL_HEIGHT = 12; 42 | 43 | DesktopPane parent; 44 | SketchData data; 45 | Color[] colorList12 = { 46 | // Brewer for up to 12 classes 47 | new Color(166, 206, 227), new Color(31, 120, 180), new Color(178, 223, 138), new Color(51, 160, 44), 48 | new Color(251, 154, 153), new Color(227, 26, 28), new Color(253, 191, 111), new Color(255, 127, 0), 49 | new Color(202, 178, 214), new Color(106, 61, 154), new Color(255, 255, 153), new Color(177, 89, 40), }; 50 | Color[] colorList9 = { 51 | // Brewer for up to 9 classes 52 | new Color(228, 26, 28), 53 | // new Color(55,126,184), 54 | new Color(26, 85, 210), 55 | // new Color(77,175,74), 56 | new Color(34, 188, 8), 57 | // new Color(152,78,163), 58 | new Color(176, 2, 207), 59 | // new Color(255,127,0), 60 | new Color(255, 105, 51), new Color(255, 255, 51), new Color(166, 86, 40), new Color(247, 129, 191), 61 | new Color(153, 153, 153), }; 62 | 63 | public List coloursCont; 64 | public List colorRampList; 65 | public List largeRampList; 66 | 67 | private Color legendColor = Color.WHITE; 68 | 69 | public Colors(DesktopPane father) { 70 | parent = father; 71 | 72 | ColourTable bToP = new ColourTable(); 73 | bToP.addContinuousColourRule((float) (0 / 1), 45, 0, 255); 74 | bToP.addContinuousColourRule((float) (1 / 1), 255, 0, 38); 75 | 76 | ColourTable bToG = new ColourTable(); 77 | bToG.addContinuousColourRule((float) (0 / 1), Color.blue.getRGB()); 78 | bToG.addContinuousColourRule((float) (1 / 1), Color.green.getRGB()); 79 | 80 | ColourTable yToR = new ColourTable(); 81 | yToR.addContinuousColourRule((float) (0 / 1), Color.yellow.getRGB()); 82 | yToR.addContinuousColourRule((float) (1 / 1), Color.red.getRGB()); 83 | 84 | ColourTable yToG = new ColourTable(); 85 | yToG.addContinuousColourRule((float) (0 / 1), Color.yellow.getRGB()); 86 | yToG.addContinuousColourRule((float) (1 / 1), Color.green.getRGB()); 87 | 88 | ColourTable spectrum = new ColourTable(); 89 | spectrum.addContinuousColourRule((float) (0), 5, 0, 206); 90 | spectrum.addContinuousColourRule((float) (0.1), 2, 96, 206); 91 | spectrum.addContinuousColourRule((float) (0.2), 10, 204, 203); 92 | spectrum.addContinuousColourRule((float) (0.3), 48, 205, 184); 93 | spectrum.addContinuousColourRule((float) (0.4), 103, 203, 168); 94 | spectrum.addContinuousColourRule((float) (0.5), 181, 232, 73); 95 | spectrum.addContinuousColourRule((float) (0.6), 255, 252, 0); 96 | spectrum.addContinuousColourRule((float) (0.7), 254, 207, 5); 97 | spectrum.addContinuousColourRule((float) (0.8), 253, 154, 0); 98 | spectrum.addContinuousColourRule((float) (0.9), 255, 77, 1); 99 | spectrum.addContinuousColourRule((float) (1.0), 255, 0, 0); 100 | 101 | coloursCont = new ArrayList(); 102 | coloursCont.add(bToP); 103 | coloursCont.add(bToG); 104 | coloursCont.add(yToR); 105 | coloursCont.add(yToG); 106 | coloursCont.add(spectrum); 107 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.YL_GN, 0, 1)); 108 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.YL_GN_BU, 0, 1)); 109 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.GN_BU, 0, 1)); 110 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.BU_GN, 0, 1)); 111 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.PU_BU_GN, 0, 1)); 112 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.PU_BU, 0, 1)); 113 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.BU_PU, 0, 1)); 114 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.RD_PU, 0, 1)); 115 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.PU_RD, 0, 1)); 116 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.OR_RD, 0, 1)); 117 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.YL_OR_RD, 0, 1)); 118 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.YL_OR_BR, 0, 1)); 119 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.PURPLES, 0, 1)); 120 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.BLUES, 0, 1)); 121 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.GREENS, 0, 1)); 122 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.ORANGES, 0, 1)); 123 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.REDS, 0, 1)); 124 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.GREYS, 0, 1)); 125 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.PU_OR, 0, 1)); 126 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.BR_B_G, 0, 1)); 127 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.P_R_GN, 0, 1)); 128 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.PI_Y_G, 0, 1)); 129 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.RD_BU, 0, 1)); 130 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.RD_GY, 0, 1)); 131 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.RD_YL_BU, 0, 1)); 132 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.SPECTRAL, 0, 1)); 133 | coloursCont.add(ColourTable.getPresetColourTable(ColourTable.RD_YL_GN, 0, 1)); 134 | 135 | colorRampList = createSwatchList(coloursCont, "small"); 136 | largeRampList = createSwatchList(coloursCont, "large"); 137 | } 138 | 139 | public List createSwatchList(List list, String size) { 140 | int w, h; 141 | if (size.equals("large")) { 142 | w = LARGE_WIDTH; 143 | h = LARGE_HEIGHT; 144 | } else if (size.equals("small")) { 145 | w = SMALL_WIDTH; 146 | h = SMALL_HEIGHT; 147 | } else { 148 | return null; 149 | } 150 | return createSwatchList(list, w, h); 151 | } 152 | 153 | public List createSwatchList(List list, int width, int height) { 154 | List icons = new ArrayList(); 155 | for (int i = 0; i < list.size(); i++) { 156 | icons.add(createSwatch(list.get(i), width, height)); 157 | } 158 | return icons; 159 | } 160 | 161 | public ImageIcon createSwatch(ColourTable colorTable, String size) { 162 | int w, h; 163 | if (size.equals("large")) { 164 | w = LARGE_WIDTH; 165 | h = LARGE_HEIGHT; 166 | } else if (size.equals("small")) { 167 | w = SMALL_WIDTH; 168 | h = SMALL_HEIGHT; 169 | } else { 170 | return null; 171 | } 172 | return createSwatch(colorTable, w, h); 173 | } 174 | 175 | public ImageIcon createSwatch(ColourTable colorTable, int width, int height) { 176 | BufferedImage swatch = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 177 | Graphics2D g = swatch.createGraphics(); 178 | for (int i = 0; i < width; i++) { 179 | Rectangle rect = new Rectangle(i, 0, 1, height); 180 | String string = Integer.toHexString(colorTable.findColour((float) i / width)); 181 | string = string.substring(2, string.length()); 182 | Color color = Color.decode("#" + string); 183 | g.setPaint(color); 184 | g.fill(rect); 185 | } 186 | return new ImageIcon(swatch); 187 | 188 | } 189 | 190 | public Color getTagColor(String key) { 191 | data = parent.data; 192 | int tagSize = parent.tagList.size(); 193 | int index = parent.tagList.indexOf(key); 194 | Color color; 195 | if (tagSize <= 9) { 196 | color = colorList9[index]; 197 | } else if (tagSize <= 12) { 198 | color = colorList12[index]; 199 | } else { 200 | if (index > colorList12.length - 1) { 201 | float num = (((float) index - 12) / ((float) tagSize - 12)) * 255; 202 | int rgbNum = 255 - (int) num; 203 | color = new Color(rgbNum, rgbNum, rgbNum); 204 | } else { 205 | color = colorList12[index]; 206 | } 207 | } 208 | return (color); 209 | } 210 | 211 | public void setLegendColor(Color c) { 212 | legendColor = c; 213 | } 214 | 215 | public Color getLegendColor() { 216 | return legendColor; 217 | } 218 | 219 | } 220 | -------------------------------------------------------------------------------- /src/main/Histo.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package main; 23 | 24 | import javax.swing.JPanel; 25 | 26 | @SuppressWarnings("serial") 27 | public class Histo extends JPanel { 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/Recorder.java: -------------------------------------------------------------------------------- 1 | /* 2 | DYNAMO Animation Tool 3 | Copyright (C) 2016 Glenn Xavier 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | 18 | */ 19 | 20 | package main; 21 | 22 | import java.awt.event.ActionEvent; 23 | import java.awt.event.ActionListener; 24 | import java.io.File; 25 | import java.io.IOException; 26 | import java.nio.file.Files; 27 | import java.nio.file.Path; 28 | import java.text.DecimalFormat; 29 | import java.util.Comparator; 30 | 31 | import javax.swing.JPanel; 32 | 33 | import net.miginfocom.swing.MigLayout; 34 | 35 | import javax.swing.JToggleButton; 36 | import javax.swing.JButton; 37 | import javax.swing.JCheckBox; 38 | import javax.swing.JLabel; 39 | import javax.swing.Timer; 40 | 41 | import org.joda.time.DateTime; 42 | import javax.swing.JComboBox; 43 | 44 | 45 | public class Recorder extends JPanel { 46 | 47 | /** 48 | * 49 | */ 50 | private static final long serialVersionUID = 1L; 51 | DesktopPane parent; 52 | SketchData data; 53 | int timeDelay = 10; 54 | ActionListener time; 55 | Timer timer; 56 | DateTime dateTime; 57 | JLabel timeLabel; 58 | JCheckBox chkTemp; 59 | JButton btnSave; 60 | 61 | public Recorder(DesktopPane father) { 62 | parent = father; 63 | data = father.data; 64 | setLayout(new MigLayout("", "[grow][][]", "[][][]")); 65 | enableRecorder(); 66 | 67 | // checkbox to store frames 68 | chkTemp = new JCheckBox("Store frames"); 69 | add(chkTemp, "cell 0 0 2,alignx left"); 70 | 71 | timeLabel = new JLabel("00.00s"); 72 | add(timeLabel, "cell 1 0 2,alignx right"); 73 | 74 | final JToggleButton tglbtnRecord = new JToggleButton("Record"); 75 | add(tglbtnRecord, "cell 0 1"); 76 | tglbtnRecord.addActionListener(new ActionListener() { 77 | public void actionPerformed(ActionEvent evt) { 78 | data.save = !data.save; 79 | if (data.save){ 80 | timer.start(); 81 | btnSave.setEnabled(false); 82 | } else { 83 | timer.stop(); 84 | btnSave.setEnabled(true); 85 | } 86 | } 87 | }); 88 | 89 | JButton btnStop = new JButton("Stop"); 90 | add(btnStop, "cell 1 1"); 91 | btnStop.addActionListener(new ActionListener() { 92 | public void actionPerformed(ActionEvent evt) { 93 | if (data.save){ 94 | timer.stop(); 95 | data.save = !data.save; 96 | tglbtnRecord.setSelected(false); 97 | btnSave.setEnabled(true); 98 | } 99 | } 100 | }); 101 | 102 | btnSave = new JButton("Save"); 103 | btnSave.setEnabled(false); 104 | add(btnSave, "cell 2 1"); 105 | 106 | // Hidden 107 | JComboBox comboBox = new JComboBox(); 108 | // add(comboBox, "flowx,cell 0 2 3 1,growx"); 109 | comboBox.addItem("h264 Baseline"); 110 | comboBox.setEnabled(false); 111 | 112 | // Hidden 113 | JComboBox comboBox_1 = new JComboBox(); 114 | // add(comboBox_1, "flowx,cell 0 2 3 1,growx"); 115 | comboBox_1.addItem("30 fps"); 116 | comboBox_1.setEnabled(false); 117 | 118 | btnSave.addActionListener(new ActionListener() { 119 | public void actionPerformed(ActionEvent evt) { 120 | try { 121 | new SequenceEncoder(parent, parent.animationTitle + parent.exportCounter + ".mp4", 122 | 0, data.frameCounter, 123 | !chkTemp.isSelected()); 124 | } catch (IOException e) { 125 | e.printStackTrace(); 126 | } 127 | 128 | data.frameCounter = 0; 129 | timeLabel.setText("00.00s"); 130 | } 131 | }); 132 | } 133 | 134 | public void enableRecorder() { 135 | time = new ActionListener() { 136 | @Override 137 | public void actionPerformed(ActionEvent evt) { 138 | double frames = ((double) data.frameCounter) / 25d; 139 | timeLabel.setText(new DecimalFormat("00.00").format(frames) + "s"); 140 | } 141 | }; 142 | timer = new Timer(timeDelay, time); 143 | } 144 | public void discardRecorder() { 145 | timer = null; 146 | data.frameCounter = 0; 147 | timeLabel.setText("00.00s"); 148 | 149 | // Delete temp folder 150 | if(!chkTemp.isSelected()) { 151 | try { 152 | Files.walk(Path.of("export/temp/"+ parent.animationTitle + parent.exportCounter)) 153 | .sorted(Comparator.reverseOrder()) 154 | .map(Path::toFile) 155 | .forEach(File::delete); 156 | } catch (IOException e) { 157 | e.printStackTrace(); 158 | } 159 | } 160 | 161 | } 162 | 163 | } -------------------------------------------------------------------------------- /src/main/SequenceEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package main; 23 | 24 | import java.awt.image.BufferedImage; 25 | import java.beans.PropertyChangeEvent; 26 | import java.beans.PropertyChangeListener; 27 | import java.io.File; 28 | import java.io.IOException; 29 | import java.nio.ByteBuffer; 30 | import java.nio.file.Files; 31 | import java.nio.file.Path; 32 | import java.util.ArrayList; 33 | import java.util.Arrays; 34 | import java.util.Comparator; 35 | import java.util.concurrent.CancellationException; 36 | import java.util.concurrent.ExecutionException; 37 | 38 | import javax.imageio.ImageIO; 39 | import javax.swing.ProgressMonitor; 40 | import javax.swing.SwingWorker; 41 | 42 | import org.jcodec.codecs.h264.H264Encoder; 43 | import org.jcodec.codecs.h264.H264Utils; 44 | import org.jcodec.common.NIOUtils; 45 | import org.jcodec.common.SeekableByteChannel; 46 | import org.jcodec.common.model.ColorSpace; 47 | import org.jcodec.common.model.Picture; 48 | import org.jcodec.containers.mp4.Brand; 49 | import org.jcodec.containers.mp4.MP4Packet; 50 | import org.jcodec.containers.mp4.TrackType; 51 | import org.jcodec.containers.mp4.muxer.FramesMP4MuxerTrack; 52 | import org.jcodec.containers.mp4.muxer.MP4Muxer; 53 | import org.jcodec.scale.AWTUtil; 54 | import org.jcodec.scale.RgbToYuv420; 55 | 56 | public class SequenceEncoder implements PropertyChangeListener { 57 | private SeekableByteChannel ch; 58 | private Picture toEncode; 59 | private RgbToYuv420 transform; 60 | private H264Encoder encoder; 61 | private ArrayList spsList; 62 | private ArrayList ppsList; 63 | private FramesMP4MuxerTrack outTrack; 64 | private ByteBuffer _out; 65 | private int frameNo; 66 | private MP4Muxer muxer; 67 | private ProgressMonitor progressMonitor; 68 | DesktopPane parent; 69 | private int previousExportCounter; 70 | Task operation; 71 | int start; 72 | int end; 73 | boolean deleteTemp; 74 | 75 | public SequenceEncoder(DesktopPane father, String name, int s, int e, boolean del) throws IOException { 76 | parent = father; 77 | File file = new File("export/"+name); 78 | start = s; 79 | end = e; 80 | deleteTemp = del; 81 | previousExportCounter = parent.exportCounter; 82 | this.ch = NIOUtils.writableFileChannel(file); 83 | 84 | // Transform to convert between RGB and YUV 85 | transform = new RgbToYuv420(0, 0); 86 | 87 | // Muxer that will store the encoded frames 88 | muxer = new MP4Muxer(ch, Brand.MP4); 89 | 90 | // Add video track to muxer 91 | outTrack = muxer.addTrackForCompressed(TrackType.VIDEO, 25); 92 | 93 | // Allocate a buffer big enough to hold output frames 94 | _out = ByteBuffer.allocate(1920 * 1080 * 6); 95 | 96 | // Create an instance of encoder 97 | encoder = new H264Encoder(); 98 | 99 | // Encoder extra data ( SPS, PPS ) to be stored in a special place of 100 | // MP4 101 | spsList = new ArrayList(); 102 | ppsList = new ArrayList(); 103 | 104 | progressMonitor = new ProgressMonitor(parent, "Encoding Video...", "", 0, 100); 105 | progressMonitor.setProgress(0); 106 | operation = new Task(this); 107 | operation.addPropertyChangeListener(this); 108 | operation.execute(); 109 | 110 | } 111 | 112 | class Task extends SwingWorker { 113 | 114 | SequenceEncoder encoder; 115 | 116 | public Task(SequenceEncoder se) { 117 | encoder = se; 118 | } 119 | 120 | @Override 121 | protected Void doInBackground() throws Exception { 122 | for (int i = start; i < end; i++) { 123 | BufferedImage bi = ImageIO.read(new File( 124 | String.format("export/temp/" + parent.animationTitle + parent.exportCounter + "/temp%08d.jpeg", i))); 125 | encoder.encodeImage(bi); 126 | setProgress((int) (100 * i) / end); 127 | } 128 | encoder.finish(); 129 | setProgress(100); 130 | parent.exportCounter++; 131 | return null; 132 | } 133 | 134 | public void done() { 135 | try { 136 | @SuppressWarnings("unused") 137 | Void result = get(); 138 | System.out.println("Video Encoding Completed"); 139 | 140 | if(deleteTemp) { 141 | // Delete temp folder 142 | Files.walk(Path.of("export/temp/"+ parent.animationTitle + previousExportCounter)) 143 | .sorted(Comparator.reverseOrder()) 144 | .map(Path::toFile) 145 | .forEach(File::delete); 146 | } 147 | } catch (InterruptedException e) { 148 | 149 | } catch (CancellationException e) { 150 | System.out.println("Encoding Cancelled...\n"); 151 | } catch (ExecutionException e) { 152 | System.out.println("Encoding Failed: " + e.getCause()); 153 | } catch (IOException e) { 154 | System.out.println("Failed to clear \"temp\" folder...\n"); 155 | e.printStackTrace(); 156 | } 157 | } 158 | } 159 | 160 | public void encodeImage(BufferedImage bi) throws IOException { 161 | if (toEncode == null) { 162 | toEncode = Picture.create(bi.getWidth(), bi.getHeight(), ColorSpace.YUV420); 163 | } 164 | 165 | // Perform conversion 166 | for (int i = 0; i < 3; i++) 167 | Arrays.fill(toEncode.getData()[i], 0); 168 | transform.transform(AWTUtil.fromBufferedImage(bi), toEncode); 169 | 170 | // Encode image into H.264 frame, the result is stored in '_out' buffer 171 | _out.clear(); 172 | ByteBuffer result = encoder.encodeFrame(_out, toEncode); 173 | 174 | // Based on the frame above form correct MP4 packet 175 | spsList.clear(); 176 | ppsList.clear(); 177 | H264Utils.encodeMOVPacket(result, spsList, ppsList); 178 | 179 | // Add packet to video track 180 | outTrack.addFrame(new MP4Packet(result, frameNo, 25, 1, frameNo, true, null, frameNo, 0)); 181 | 182 | frameNo++; 183 | } 184 | 185 | public void finish() throws IOException { 186 | // Push saved SPS/PPS to a special storage in MP4 187 | outTrack.addSampleEntry(H264Utils.createMOVSampleEntry(spsList, ppsList)); 188 | 189 | // Write MP4 header and finalize recording 190 | muxer.writeHeader(); 191 | NIOUtils.closeQuietly(ch); 192 | 193 | 194 | } 195 | 196 | @Override 197 | public void propertyChange(PropertyChangeEvent evt) { 198 | if ("progress" == evt.getPropertyName()) { 199 | int progress = (Integer) evt.getNewValue(); 200 | progressMonitor.setProgress(progress); 201 | } 202 | if (progressMonitor.isCanceled()) { 203 | operation.cancel(true); 204 | } 205 | 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/main/Sketch.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package main; 23 | 24 | import java.net.URL; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | import java.util.Map.Entry; 28 | 29 | import gui.ControlPanel; 30 | import utils.PointRecord; 31 | import utils.Track; 32 | 33 | import com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode; 34 | import com.jogamp.opengl.GLProfile; 35 | 36 | import org.joda.time.DateTime; 37 | import org.joda.time.Hours; 38 | import org.joda.time.Minutes; 39 | import org.joda.time.Seconds; 40 | 41 | import processing.core.PApplet; 42 | import processing.core.PShape; 43 | import processing.opengl.PJOGL; 44 | import de.fhpotsdam.unfolding.UnfoldingMap; 45 | import de.fhpotsdam.unfolding.events.EventDispatcher; 46 | import de.fhpotsdam.unfolding.geo.Location; 47 | import de.fhpotsdam.unfolding.utils.MapUtils; 48 | import de.fhpotsdam.unfolding.utils.ScreenPosition; 49 | 50 | public class Sketch extends PApplet { 51 | // Connect processing sketch to the rest of the application 52 | private DesktopPane parent; 53 | private SketchData data; 54 | private ControlPanel controlPanel; 55 | 56 | // 57 | public void setParent(DesktopPane father) { 58 | parent = father; 59 | data = parent.data; 60 | controlPanel = parent.controlPanel; 61 | } 62 | 63 | public Legend legend; 64 | public UnfoldingMap map; 65 | // 66 | public boolean leftMapNeeded = false; 67 | public boolean rightMapNeeded = false; 68 | public UnfoldingMap leftMap; 69 | public UnfoldingMap rightMap; 70 | 71 | int colorMin; 72 | int colorMax; 73 | int colorMid; 74 | 75 | EventDispatcher eventDispatcher; 76 | 77 | // RUN/EXIT BEHAVIOURS ----------------- 78 | public void run(int x, int y) { 79 | String[] processingArgs = {"--location="+x+","+y, "DynamoVis Animation"}; 80 | PApplet.runSketch(processingArgs, this); 81 | } 82 | // Overriden to prevent System.exit(0) command, that 83 | // shuts down the whole java environment 84 | @Override 85 | public void exitActual() { 86 | // minimize the window if it doesn't get disposed 87 | getSurface().setVisible(false); 88 | 89 | // hide timeline and control panel 90 | parent.controlContainer.setVisible(false); 91 | parent.timelineContainer.setVisible(false); 92 | 93 | // get ready for another animation 94 | parent.sketch = null; 95 | parent.startup = true; 96 | parent.dataConfigPanel.SetComponentsEnabled(true); 97 | 98 | noLoop(); 99 | } 100 | //// 101 | 102 | int w, h; 103 | public boolean isExiting = false; 104 | public void setSize(int w, int h) { 105 | this.w = w; 106 | this.h = h; 107 | } 108 | // setup is replaced by settings in Processing 3 109 | public void settings() { 110 | GLProfile.initSingleton(); 111 | size(w, h, P3D); 112 | 113 | // Set window icon 114 | String iconFilename = DesktopPane.isMacOSX() ? "logo1024.png" : "logo32.png"; 115 | URL res = parent.getClass().getClassLoader().getResource(iconFilename); 116 | if(res.getProtocol().equals("jar")) { 117 | PJOGL.setIcon(iconFilename); // jar file contains the resource in its root directory 118 | } else { 119 | PJOGL.setIcon(res.getPath()); // source compilation can find the resource in bin directory 120 | } 121 | } 122 | 123 | public void setup() { 124 | colorMode(HSB, 360, 100, 100); 125 | frameRate(60); 126 | 127 | // Closes only the sketch on exit 128 | if (getGraphics().isGL() && !DesktopPane.isMacOSX()) { 129 | final com.jogamp.newt.Window w = (com.jogamp.newt.Window) getSurface().getNative(); 130 | w.setDefaultCloseOperation(WindowClosingMode.DISPOSE_ON_CLOSE); 131 | // w.setAlwaysOnTop(true); 132 | } 133 | // else { 134 | // // Not Tested 135 | // final JFrame w = (JFrame) getSurface().getNative(); 136 | // w.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 137 | // } 138 | 139 | // NONOPENGL ICON SETUP 140 | // PImage icon = loadImage(parent.getClass().getResource("logo32.png").getPath()); 141 | // surface.setIcon(icon); 142 | 143 | parent.dataPoints = null; 144 | println("Animation Dimensions: " + w + "x" + h); 145 | println("Polling Interval: " + data.dataInterval + " " + data.timeUnit); 146 | 147 | // 148 | leftMapNeeded = data.needLeftMap; 149 | rightMapNeeded = data.needRightMap; 150 | map = new UnfoldingMap(this, "0", 0, 0, w, h, false, false, data.provider); 151 | 152 | map.zoomAndPanToFit(data.locations); 153 | if(!leftMapNeeded && !rightMapNeeded) map.setTweening(true); 154 | eventDispatcher = MapUtils.createDefaultEventDispatcher(this, map); 155 | map.zoomAndPanToFit(data.locations); // sometimes the first attempt zooms too far and bugs out, so do it again 156 | 157 | // extra maps 158 | if(leftMapNeeded) leftMap = createWrappedMap(map, eventDispatcher, 1); 159 | if(rightMapNeeded) rightMap = createWrappedMap(map, eventDispatcher, 2); 160 | 161 | // 162 | legend = new Legend(this, data, parent, map); 163 | resetLegend(); 164 | println(); 165 | } 166 | /// extra map functions 167 | // https://github.com/tillnagel/unfolding/commit/46d03cf6ebc6e01a35dc0aede0a02b428b9cf68d 168 | public UnfoldingMap createWrappedMap(UnfoldingMap mainMap, EventDispatcher eventDispatcher, int id) { 169 | float x = id==1 ? -w : w; 170 | UnfoldingMap wrappedMap = new UnfoldingMap(this, Integer.toString(id), x, 0, w, h, false, false, data.provider); 171 | wrappedMap.zoomToLevel(mainMap.getZoomLevel()); 172 | eventDispatcher.register(wrappedMap, "zoom", mainMap.getId()); 173 | return wrappedMap; 174 | } 175 | public void updateMap(UnfoldingMap mainMap, UnfoldingMap nextMap, boolean left) { 176 | float degree = (left) ? -180 : 180; 177 | 178 | // Move next map 179 | ScreenPosition pos = mainMap.getScreenPosition(new Location(0, degree)); 180 | nextMap.move(pos.x, 0); 181 | if (left) { 182 | nextMap.moveBy(-800, 0); 183 | } 184 | 185 | // Pan next map 186 | nextMap.panTo(new Location(0, 0)); 187 | ScreenPosition map1RightPos = mainMap.getScreenPosition(new Location(0, degree)); 188 | Location map1RightLocation = nextMap.getLocation(map1RightPos); 189 | float lonDiff = (-map1RightLocation.getLon()) - degree; 190 | nextMap.panTo(new Location(-map1RightLocation.getLat(), lonDiff)); 191 | 192 | // Ensure next map is always over main map (push 1px) 193 | nextMap.panBy( (left ? 1 : -1), 0); 194 | } 195 | //// 196 | 197 | // 198 | public void draw() { 199 | background(0, 0, 35); 200 | 201 | if(leftMapNeeded) updateMap(map, leftMap, true); 202 | if(rightMapNeeded) updateMap(map, rightMap, false); 203 | if(!isExiting) { 204 | map.draw(); 205 | if(leftMapNeeded) leftMap.draw(); 206 | if(rightMapNeeded) rightMap.draw(); 207 | } 208 | 209 | for (Entry entry : parent.trackList.entrySet()) { 210 | // 211 | String key = entry.getKey(); 212 | Track track = entry.getValue(); 213 | 214 | // if the data is not showing, skip draw the path 215 | if (!track.getVisibility()) continue; 216 | 217 | int color = parent.colors.getTagColor(key).getRGB(); 218 | ArrayList points = track.getPoints(); 219 | 220 | // TODO: Add brushedTag visualization here if we implement timeline features 221 | 222 | // Underlay 223 | if(data.ghost) { 224 | pushStyle(); 225 | beginShape(); 226 | noFill(); 227 | stroke(data.ghostColor.getRGB(), data.ghostAlpha); 228 | strokeWeight(data.ghostWeight); 229 | 230 | for (int i = 0; i < points.size(); i++) { 231 | PointRecord marker = points.get(i); 232 | DateTime markerTime = marker.getTime(); 233 | if (markerTime.isBefore(data.currentTime) || markerTime.isEqual(data.currentTime)) { 234 | ScreenPosition pos = map.getScreenPosition(marker.getLocation()); 235 | 236 | vertex(pos.x, pos.y); 237 | } 238 | } 239 | endShape(); // draws underlay 240 | popStyle(); 241 | } 242 | 243 | // Track visualizations 244 | if (data.strokeColorToggle || (data.strokeWeightToggle && data.strokeWeightSelection != null)) { 245 | pushStyle(); 246 | beginShape(); 247 | noFill(); 248 | strokeWeight(4); 249 | strokeJoin(ROUND); // make line connections rounded 250 | for (int i = 0; i < points.size(); i++) { 251 | PointRecord marker = points.get(i); 252 | DateTime markerTime = marker.getTime(); 253 | if (markerTime.isBefore(data.currentTime) || markerTime.isEqual(data.currentTime)) { 254 | ScreenPosition pos = map.getScreenPosition(marker.getLocation()); 255 | 256 | int hours; 257 | if (data.timeUnit.equals("minutes")) { 258 | hours = Hours.hoursBetween(markerTime, data.currentTime).getHours(); 259 | } else { 260 | hours = Minutes.minutesBetween(markerTime, data.currentTime).getMinutes(); 261 | } 262 | float alpha = 255; 263 | if (data.falloff) { 264 | alpha = constrain(map(hours, 0, data.alphaMaxHours, 255, 0), 0, 255); 265 | } 266 | 267 | if (hours <= 24) { 268 | stroke(360, 100, 100, alpha); 269 | } else if (hours <= 48) { 270 | stroke(360, 100, 63, alpha); 271 | } else if (hours <= 72) { 272 | stroke(360, 100, 30, alpha); 273 | } 274 | 275 | if (alpha != 0) { 276 | if (data.strokeWeightToggle && data.strokeWeightSelection != null) { 277 | String strokeWeightVar = data.strokeWeightSelection; 278 | float strokeWeightValue = (Float) marker.getProperty(strokeWeightVar); 279 | float strokeWeight = map(strokeWeightValue, parent.attributes.getMin(strokeWeightVar), 280 | parent.attributes.getMax(strokeWeightVar), data.strokeWeightMin, 281 | data.strokeWeightMax); 282 | strokeWeight(strokeWeight); 283 | } 284 | 285 | if (data.strokeColorToggle) { 286 | String strokeColorVar = data.strokeColorSelection; 287 | if (strokeColorVar.equals(parent.attributes.getIndex())) { 288 | stroke(color, alpha); 289 | } else { 290 | float strokeColorValue = (Float) marker.getProperty(strokeColorVar); 291 | float strokeColorPercent = norm(strokeColorValue, 292 | parent.attributes.getMin(strokeColorVar), 293 | parent.attributes.getMax(strokeColorVar)); 294 | int strokeColor = parent.colors.coloursCont.get(data.selectedLineSwatch) 295 | .findColour(strokeColorPercent); 296 | stroke(strokeColor, alpha); 297 | } 298 | vertex(pos.x, pos.y); 299 | } 300 | } 301 | } 302 | } 303 | endShape(); // draw tracks 304 | popStyle(); 305 | } 306 | 307 | // Point or vector visualizations 308 | if(data.vectorToggle || data.pointColorToggle) { 309 | for (int i = 0; i < points.size(); i++) { 310 | PointRecord marker = points.get(i); 311 | DateTime markerTime = marker.getTime(); 312 | if (markerTime.isBefore(data.currentTime) || markerTime.isEqual(data.currentTime)) { 313 | ScreenPosition pos = map.getScreenPosition(marker.getLocation()); 314 | 315 | int hours; 316 | if (data.timeUnit.equals("minutes")) { 317 | hours = Hours.hoursBetween(markerTime, data.currentTime).getHours(); 318 | } else { 319 | hours = Minutes.minutesBetween(markerTime, data.currentTime).getMinutes(); 320 | } 321 | float alpha = 255; 322 | if (data.falloff) { 323 | alpha = constrain(map(hours, 0, data.alphaMaxHours, 255, 0), 0, 255); 324 | } 325 | 326 | if (hours <= 24) { 327 | fill(360, 100, 100, alpha); 328 | } else if (hours <= 48) { 329 | fill(360, 100, 63, alpha); 330 | } else if (hours <= 72) { 331 | fill(360, 100, 30, alpha); 332 | } 333 | 334 | if (alpha != 0) { 335 | if (data.pointColorToggle) { 336 | pushStyle(); 337 | float size = 7; 338 | String pointColorVar = data.pointColorSelection; 339 | if (pointColorVar.equals(parent.attributes.getIndex())) { 340 | fill(color, alpha); 341 | } else { 342 | float pointColorValue = (Float) marker.getProperty(pointColorVar); 343 | float pointColorPercent = norm(pointColorValue, 344 | parent.attributes.getMin(pointColorVar), 345 | parent.attributes.getMax(pointColorVar)); 346 | int strokeColor = parent.colors.coloursCont.get(data.selectedPointSwatch) 347 | .findColour(pointColorPercent); 348 | fill(strokeColor, alpha); 349 | } 350 | if (data.pointSizeToggle) { 351 | String pointSizeVar = data.pointSizeSelection; 352 | float pointSizeValue = (Float) marker.getProperty(pointSizeVar); 353 | float pointSize = map(pointSizeValue, parent.attributes.getMin(pointSizeVar), 354 | parent.attributes.getMax(pointSizeVar), data.pointSizeMin, 355 | data.pointSizeMax); 356 | size = pointSize; 357 | } 358 | ellipse(pos.x, pos.y, size, size); 359 | popStyle(); 360 | } 361 | 362 | if (data.vectorToggle) { 363 | pushStyle(); 364 | String vectorFieldVar = data.vectorFieldSelection; 365 | float radius = (Float) marker.getProperty(vectorFieldVar); 366 | float length = 10; 367 | if (data.vectorLengthToggle) { 368 | length = map(radius, parent.attributes.getMin(vectorFieldVar), 369 | parent.attributes.getMax(vectorFieldVar), data.vectorLengthMin, 370 | data.vectorLengthMax); 371 | } 372 | float heading = (Float) marker.getProperty(data.headingFieldSelection); 373 | float x = cos(radians(heading)) * length; 374 | float y = sin(radians(heading)) * length; 375 | if (data.vectorColorToggle) { 376 | String vectorColorVar = data.vectorColorSelection; 377 | if (vectorColorVar.equals(parent.attributes.getIndex())) { 378 | stroke(color, alpha); 379 | } else { 380 | float vectorColorValue = (Float) marker.getProperty(vectorColorVar); 381 | float vectorColorPercent = norm(vectorColorValue, 382 | parent.attributes.getMin(vectorColorVar), 383 | parent.attributes.getMax(vectorColorVar)); 384 | int vectorColor = parent.colors.coloursCont.get(data.selectedVectorSwatch) 385 | .findColour(vectorColorPercent); 386 | stroke(vectorColor, alpha); 387 | } 388 | } else { 389 | stroke(0, 0, 100, alpha); 390 | } 391 | strokeWeight(2); 392 | line(pos.x, pos.y, pos.x + x, pos.y + y); 393 | popStyle(); 394 | } 395 | } 396 | } 397 | } 398 | } 399 | } 400 | 401 | // advance time every x frames 402 | if (!data.pause && !data.mouse && frameCount % data.speed == 0) { 403 | 404 | if (data.currentTime.isBefore(data.endTime.plusMinutes(1))) { 405 | if (data.timeUnit.equals("minutes")) { 406 | data.currentTime = data.currentTime.plusMinutes(data.dataInterval); 407 | } else if (data.timeUnit.equals("seconds")) { 408 | data.currentTime = data.currentTime.plusSeconds(data.dataInterval); 409 | } 410 | } 411 | 412 | if (data.timeUnit.equals("minutes")) { 413 | data.seek = Minutes.minutesBetween(data.startTime, data.currentTime).getMinutes(); 414 | } else if (data.timeUnit.equals("seconds")) { 415 | data.seek = Seconds.secondsBetween(data.startTime, data.currentTime).getSeconds(); 416 | } 417 | 418 | data.seek = data.seek / data.dataInterval; 419 | controlPanel.seek.setValue(data.seek); 420 | 421 | if (data.currentTime.isAfter(data.endTime) && data.loop) { 422 | data.currentTime = data.startTime; 423 | } 424 | } 425 | 426 | if(!isExiting) { 427 | legend.display(); 428 | legend.drag(mouseX, mouseY); 429 | } 430 | 431 | // Export 432 | if (data.save) { 433 | String file = String.format("export/temp/" + parent.animationTitle + parent.exportCounter + "/temp%08d.jpeg", 434 | data.frameCounter); 435 | saveFrame(file); 436 | data.frameCounter++; 437 | } 438 | 439 | // Display approproate text if the animation window is terminated but the window itself is lingering 440 | if (isExiting) { 441 | textFont(legend.font2); 442 | background(20); 443 | fill(245); 444 | textAlign(CENTER, CENTER); 445 | text("\"" + parent.animationTitle + "\" animation was terminated.\nFeel free to close this window.", width/2, height/2); 446 | 447 | exitActual(); 448 | } 449 | } 450 | 451 | // 452 | public void resetLegend() { 453 | legend.setLocation(0, height - 40); 454 | } 455 | 456 | public void keyPressed() { 457 | switch (key) { 458 | case 'z': 459 | zoomIn(); 460 | break; 461 | case 'x': 462 | zoomOut(); 463 | break; 464 | case 'c': 465 | zoomAndPan(data.locations); 466 | break; 467 | } 468 | } 469 | 470 | // 471 | public void zoomIn() { 472 | map.zoomIn(); 473 | if(leftMap != null) leftMap.zoomIn(); 474 | if(rightMap != null) rightMap.zoomIn(); 475 | } 476 | public void zoomOut() { 477 | map.zoomOut(); 478 | if(leftMap != null) leftMap.zoomOut(); 479 | if(rightMap != null) rightMap.zoomOut(); 480 | } 481 | public void zoomAndPan(List locations) { 482 | map.zoomAndPanToFit(locations); 483 | if(leftMap != null) leftMap.zoomAndPanToFit(locations); 484 | if(rightMap != null) rightMap.zoomAndPanToFit(locations); 485 | } 486 | 487 | public void register() { 488 | eventDispatcher.register(map, "pan", map.getId()); 489 | } 490 | 491 | public void unregister() { 492 | eventDispatcher.unregister(map, "pan", map.getId()); 493 | } 494 | 495 | public void mousePressed() { 496 | legend.clicked(mouseX, mouseY); 497 | } 498 | 499 | public void mouseReleased() { 500 | legend.stopDragging(); 501 | } 502 | 503 | public void mouseMoved() { 504 | 505 | } 506 | 507 | 508 | } 509 | -------------------------------------------------------------------------------- /src/main/SketchData.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package main; 23 | 24 | import utils.PointRecord; 25 | import utils.Track; 26 | 27 | import java.awt.Color; 28 | import java.awt.Rectangle; 29 | import java.util.ArrayList; 30 | import java.util.HashMap; 31 | import java.util.Hashtable; 32 | import java.util.List; 33 | import java.util.Map; 34 | import java.util.Map.Entry; 35 | 36 | import javax.swing.JCheckBox; 37 | 38 | import org.joda.time.DateTime; 39 | 40 | import de.fhpotsdam.unfolding.geo.Location; 41 | import de.fhpotsdam.unfolding.providers.AbstractMapProvider; 42 | import de.fhpotsdam.unfolding.utils.GeoUtils; 43 | import de.fhpotsdam.unfolding.utils.ScreenPosition; 44 | 45 | public class SketchData { 46 | 47 | public ArrayList Times = null; 48 | public ArrayList All_the_Times = new ArrayList(); 49 | public Hashtable> Times_hash = null; 50 | public Location[] mapExtent; 51 | public List locations; 52 | public HashMap> fieldMinMax; 53 | 54 | public DateTime startTime; 55 | public DateTime endTime; 56 | public DateTime currentTime; 57 | 58 | public DateTime user_end_time; 59 | public DateTime user_start_time; 60 | 61 | // setting for boundary visualization 62 | public ArrayList Bdy_hull = new ArrayList(); // storing all the points that forming the 63 | // convex hull 64 | public boolean Bdy_Viz_Enable; 65 | public Color Bdy_Viz_Color = new Color(255, 255, 255, 255); 66 | public Color Bdy_Viz_Stroke_Color = Color.RED; 67 | public int Bdy_Viz_Stroke_Weight = 5; 68 | public boolean Bdy_Viz_Panel_Close = false; 69 | public boolean Bdy_Viz_Changes = false; 70 | public boolean init_setting = true; 71 | public int boundaryStartYear; 72 | public int boundaryEndYear; 73 | public int boundaryStartMonth; 74 | public int boundaryEndMonth; 75 | public int boundaryStartDate; 76 | public int boundaryEndDate; 77 | public boolean boundarySelect = true; 78 | public boolean drawBoundary; 79 | public int totalTime; 80 | public int dataInterval; 81 | public String timeUnit; 82 | public boolean needRightMap = false; 83 | public boolean needLeftMap = false; 84 | 85 | 86 | // setting for enable the time selection of the time line with boundary 87 | // visualization 88 | public JCheckBox enable_check = new JCheckBox("Enable"); 89 | 90 | public int seek; 91 | public int alphaMaxHours; 92 | public int speed; 93 | 94 | public boolean falloff; 95 | public boolean pause = true; 96 | public boolean mouse = false; 97 | public boolean loop; 98 | public boolean strokeWeightToggle; 99 | public boolean pointColorToggle; 100 | public boolean pointSizeToggle; 101 | public boolean strokeColorToggle; 102 | public boolean vectorToggle; 103 | public boolean vectorLengthToggle; 104 | public boolean vectorColorToggle; 105 | public boolean boundaryColorToggle; 106 | 107 | public String strokeWeightSelection; 108 | public String pointColorSelection; 109 | public String pointSizeSelection; 110 | public String strokeColorSelection; 111 | public String selectedColorUnit; 112 | public String selectedStrokeWeightUnit; 113 | public String vectorFieldSelection; 114 | public String headingFieldSelection; 115 | public String vectorColorSelection; 116 | public String boundaryColorSelection; 117 | 118 | public int strokeWeightMin = 1; 119 | public int strokeWeightMax = 10; 120 | public int pointSizeMin = 1; 121 | public int pointSizeMax = 10; 122 | public int vectorLengthMin = 5; 123 | public int vectorLengthMax = 20; 124 | 125 | public boolean ghost; 126 | public Color ghostColor = Color.WHITE; 127 | public int ghostAlpha; 128 | public int ghostWeight; 129 | 130 | // Settings for boundary visit (Activity Space Panel) 131 | public boolean drawChart = false; // commented out: no longer needed 132 | public boolean boundary; // checking whether need to map the boundary 133 | public boolean drawBuffer = false; // checking whether generate buffer file 134 | public boolean highlight_all; // no longer needed 135 | public boolean highlight_fly; // checking whether visualize on the fly boundary visit 136 | public boolean includeFilteredPts = false;; // Allow user to select if filtered points are mapped 137 | public Color boundaryColor = Color.BLACK; // stroke color for convex hull boundary 138 | public Color highlightColor = Color.WHITE; // point highlight color 139 | public int highlightAlpha; // opacity for point color 140 | public int boundaryAlpha; // opacity for boundary color 141 | public int highlightWeight; // stroke weight for point 142 | public int boundaryWeight = 2; // stroke weight for boundary 143 | public int numSect; // sector number for boundary 144 | public boolean bvFile = false; // whether user selected generating buffer file 145 | public ArrayList visitedPoints = new ArrayList(); // int array for indicating if the point visit 146 | // the boundary 147 | public Hashtable hullPos; // use for tracking index of points that visit boundary 148 | public double boundaryDist = 5; // buffer size 149 | public int confidenceInterval = 100; // confidence interval for filtering points 150 | public ArrayList hull = new ArrayList(); // storing all the points that forming the convex 151 | // hull 152 | public ArrayList selectedPoints; // 153 | public String selectedID; // selected tag from the dropdown 154 | public ArrayList numVisit = new ArrayList();; // storing the number of buffer visits 155 | public ArrayList finalSectorName = new ArrayList(); // storing the sector name 156 | public int finalnumSect = 0; 157 | public boolean updateConfidenceInterval = false; 158 | public boolean updateSelectedID = true; 159 | public ArrayList clonePt = new ArrayList(); 160 | public Hashtable> filteredPts = new Hashtable>(); 161 | public int filteredPoints = 0; 162 | public int currentNumOfPoints = 0; 163 | public int pointsNeedRemove; 164 | // End Boundary setting 165 | 166 | public Location mapCenter; 167 | 168 | public boolean legendLocked = true; 169 | public boolean save = false; 170 | public int frameCounter = 0; 171 | 172 | public AbstractMapProvider provider; 173 | public PointRecord points; 174 | 175 | public int selectedLineSwatch; 176 | public int selectedBoundarySwatch; 177 | public int selectedPointSwatch; 178 | public int selectedVectorSwatch; 179 | 180 | public Map fieldColors = new HashMap(); 181 | public String brushedTag; 182 | 183 | // public int[] visitBoundary; 184 | // public String[] sector; 185 | 186 | // time Box Variables 187 | public int timeBoxStartYear; 188 | public int timeBoxStartMonth; 189 | public int timeBoxEndYear; 190 | public int timeBoxEndMonth; 191 | public boolean labelMonth = false; // for labeling cubes 192 | public boolean timeBoxBdyHighlight = false; // highlight interactions in 3D 193 | public boolean stbclose = false; 194 | public boolean boxvisible = false; 195 | 196 | public boolean resetBox = false; 197 | public boolean staticBox = false;// make static box 198 | public Rectangle boundingBox = null; 199 | Map bounds = new HashMap();// All the bounding boxes for each track 200 | public ScreenPosition coords; 201 | 202 | // boundary interaction variable 203 | public boolean overbound1 = false; // test if in other boundary 204 | public boolean overbound2 = false; 205 | public boolean highlight_interaction_boundary = false;// highlight 206 | public boolean pointInteract = false; // test if current point is interacting 207 | public boolean noInteraction = true;// the two tags do not interact true 208 | public boolean tagChange = false; 209 | 210 | // Interactions variables 211 | public boolean multipleAnimals;// boolean for if there is data for multiple animals or not 212 | public String id1; // ID value of first animal selected to highlight interactions 213 | public String id2; // ID value of second animal selected to highlight interactions 214 | public String[] selectedIDs;// array of two selected IDs 215 | public Track track1;// track of first animal selected to highlight interactions 216 | public Track track2;// track of second animal selected to highlight interactions 217 | public float highlightSize = 15;// size of highlighted points for when animals interacting 218 | public float xpos;// x position of current point 219 | public float ypos;// y position of current point 220 | public boolean highlightOnFly = false;// checkbox user option. Highlights circular buffer when interacting 221 | public boolean highlightAllInteractions = false;// checkbox user option. Highlights all points where interacting 222 | public double bufferDist;// buffer distance tolerance (user selection) 223 | public double bufferTime;// buffer time tolerance (user selection) 224 | public boolean interactionsGenerated = false;// if all user selections are up to date, interactionsGenerated == true 225 | public boolean upToDate = false;// is false if user has changed selections since last pressing Generate Buffer 226 | // button 227 | public ArrayList interactingPoints;// boolean array of all all points, true if interacting, false if 228 | // otherwise 229 | public float holdAlpha; 230 | // 231 | 232 | // 233 | // public Layer layer; 234 | public boolean layerOpt = false; 235 | public boolean onetime = false; 236 | public String geoJson; 237 | 238 | public void processFeatureList(HashMap data) { 239 | 240 | locations = new ArrayList(); 241 | 242 | for (Entry entry : data.entrySet()) { 243 | Track track = entry.getValue(); 244 | 245 | if(track.requiresLeftMap) needLeftMap = true; 246 | if(track.requiresRightMap) needRightMap = true; 247 | 248 | for (PointRecord point : track.getPoints()) { 249 | locations.add(point.getLocation()); 250 | } 251 | } 252 | mapExtent = GeoUtils.getBoundingBox(locations); 253 | System.out.println("Setting Map Extent to: " + mapExtent[0] + " " + mapExtent[1]); 254 | 255 | currentTime = startTime; 256 | 257 | System.gc(); 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /src/utils/Attributes.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | package utils; 22 | 23 | import java.util.ArrayList; 24 | 25 | public class Attributes { 26 | 27 | private ArrayList fields = new ArrayList(); 28 | private String index; 29 | 30 | public void addField(Field field) { 31 | this.fields.add(field); 32 | } 33 | 34 | public ArrayList getSelectedFields() { 35 | ArrayList selectedFields = new ArrayList(); 36 | for (Field field : fields) { 37 | if (field.getSelected()) { 38 | selectedFields.add(field); 39 | } 40 | } 41 | return selectedFields; 42 | } 43 | 44 | public ArrayList getSelectedFieldNames() { 45 | ArrayList names = new ArrayList(); 46 | for (Field field : this.getSelectedFields()) { 47 | names.add(field.getAlias()); 48 | } 49 | return names; 50 | } 51 | 52 | public ArrayList getFields() { 53 | return this.fields; 54 | } 55 | 56 | public boolean checkIfFieldExists(String s) { 57 | for (Field field : fields) { 58 | if (field.getName() == s) { 59 | return true; 60 | } 61 | } 62 | return false; 63 | } 64 | 65 | public ArrayList getAliasList() { 66 | ArrayList list = new ArrayList(); 67 | for (Field field : fields) { 68 | String s = field.getAlias(); 69 | list.add(s); 70 | } 71 | return list; 72 | } 73 | 74 | public String getName(String alias) { 75 | for (Field field : fields) { 76 | if (field.getAlias() == alias) { 77 | return field.getName(); 78 | } 79 | } 80 | return null; 81 | } 82 | 83 | public String getAlias(String name) { 84 | for (Field field : fields) { 85 | if (field.getName() == name) { 86 | return field.getAlias(); 87 | } 88 | } 89 | return null; 90 | } 91 | 92 | public void setIndex(String name) { 93 | this.index = name; 94 | } 95 | 96 | public String getIndex() { 97 | return this.index; 98 | } 99 | 100 | public String getIndexAlias() { 101 | return getAlias(this.index); 102 | } 103 | 104 | public String getUnit(String s) { 105 | String unit = null; 106 | for (Field field : fields) { 107 | if (field.getName() == s) { 108 | unit = field.getUnit(); 109 | } 110 | } 111 | return unit; 112 | } 113 | 114 | public float getMin(String s) { 115 | float min = 0; 116 | for (Field field : fields) { 117 | if (field.getName() == s) { 118 | min = field.getMin(); 119 | } 120 | } 121 | return min; 122 | } 123 | 124 | public float getMax(String s) { 125 | float max = 0; 126 | for (Field field : fields) { 127 | if (field.getName() == s) { 128 | max = field.getMax(); 129 | } 130 | } 131 | return max; 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /src/utils/Field.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package utils; 23 | 24 | public class Field { 25 | 26 | private String name; 27 | private String alias; 28 | private String unit = null; 29 | private float min; 30 | private float max; 31 | private boolean selected; 32 | 33 | public Field(String n) { 34 | setName(n); 35 | } 36 | 37 | public Field(String n, String a, String u, float min, float max, boolean selected) { 38 | setName(n); 39 | setAlias(a); 40 | setUnit(u); 41 | setMin(min); 42 | setMax(max); 43 | setSelected(selected); 44 | } 45 | 46 | public void setSelected(boolean s) { 47 | this.selected = s; 48 | } 49 | 50 | public boolean getSelected() { 51 | return this.selected; 52 | } 53 | 54 | public void setName(String n) { 55 | this.name = n; 56 | } 57 | 58 | public String getName() { 59 | return this.name; 60 | } 61 | 62 | public void setAlias(String a) { 63 | this.alias = a; 64 | } 65 | 66 | public String getAlias() { 67 | return this.alias; 68 | } 69 | 70 | public void setUnit(String u) { 71 | this.unit = u; 72 | } 73 | 74 | public String getUnit() { 75 | return this.unit; 76 | } 77 | 78 | public void setMin(float m) { 79 | this.min = m; 80 | } 81 | 82 | public float getMin() { 83 | return this.min; 84 | } 85 | 86 | public void setMax(float m) { 87 | this.max = m; 88 | } 89 | 90 | public float getMax() { 91 | return this.max; 92 | } 93 | 94 | public String printInfo() { 95 | return getName() + " " + getAlias() + " " + getUnit() + " " + getMin() + " " + getMax() + " " + getSelected(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/utils/PointRecord.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package utils; 23 | 24 | import java.util.HashMap; 25 | 26 | import org.joda.time.DateTime; 27 | 28 | import de.fhpotsdam.unfolding.geo.Location; 29 | 30 | public class PointRecord { 31 | 32 | // public static final Comparator POLAR_ORDER = null; 33 | private Location location; 34 | private int sectorNum; 35 | private String tag; 36 | private DateTime timestamp; 37 | private boolean buff; 38 | private HashMap properties = new HashMap(); 39 | 40 | // a flag for the edge of map condition 41 | @SuppressWarnings("unused") 42 | private boolean altered = false; 43 | 44 | /* 45 | * buffer_size_space takes in two points and the selected buffer value to 46 | * calculate if the distance between two points is within buffer 47 | */ 48 | public boolean buffer_size_space(Location pt_one, Location pt_two, double buffer) { 49 | double distance = Math.sqrt(Math.pow(pt_one.x - pt_two.x, 2) + Math.pow(pt_one.y - pt_two.y, 2)); 50 | if (distance <= buffer) 51 | return true; 52 | return false; 53 | } 54 | 55 | public void calculateDistance(double radius, double x, double y, double a, double b, double c) { 56 | // Finding the distance of line from center. 57 | double dist = (Math.abs(a * x + b * y + c)) / Math.sqrt(a * a + b * b); 58 | // Checking if the distance is less than, 59 | // greater than or equal to radius. 60 | this.buff = (radius > dist || radius == dist); 61 | } 62 | 63 | public void setBuff(boolean b) { 64 | this.buff = b; 65 | } 66 | 67 | public boolean getBuff() { 68 | return this.buff; 69 | } 70 | 71 | public void setSectorNum(int num) { 72 | this.sectorNum = num; 73 | } 74 | 75 | public int getSectorNum() { 76 | return this.sectorNum; 77 | } 78 | 79 | // public boolean getBuffer(){ 80 | // return this.buff.b; 81 | // } 82 | // 83 | // public void setBuffer(boolean b){ 84 | // this.buff.b = b; 85 | // } 86 | 87 | public Location getLocation() { 88 | return this.location; 89 | } 90 | 91 | public void setLocation(float x, float y) { 92 | this.location = new Location(x, y); 93 | } 94 | // wrapping around the edge of map 95 | public void adjustNegativeLongitudes() { 96 | if(this.location.y < 0) { this.location.y += 360; altered = true; } 97 | } 98 | public void adjustPositiveLongitudes() { 99 | if(this.location.y > 0) { this.location.y -= 360; altered = true; } 100 | } 101 | 102 | public void setID(String id) { 103 | this.tag = id; 104 | } 105 | 106 | public String getID() { 107 | return this.tag; 108 | } 109 | 110 | public void setTime(DateTime time) { 111 | this.timestamp = time; 112 | } 113 | 114 | public DateTime getTime() { 115 | return this.timestamp; 116 | } 117 | 118 | public int getYear() { 119 | return this.timestamp.getYear(); 120 | } 121 | 122 | public int getMonth() { 123 | return this.timestamp.getMonthOfYear(); 124 | } 125 | 126 | public int getDay() { 127 | return this.timestamp.getDayOfMonth(); 128 | } 129 | 130 | public HashMap getProperties() { 131 | return this.properties; 132 | } 133 | 134 | public Object getProperty(String key) { 135 | return this.properties.get(key); 136 | } 137 | 138 | public Object addProperty(String key, Object value) { 139 | return this.properties.put(key, value); 140 | } 141 | 142 | public void removeProperty(String key) { 143 | this.properties.remove(key); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /src/utils/Track.java: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DynamoVis Animation Tool 4 | Copyright (C) 2016 Glenn Xavier 5 | UPDATED: 2021 Mert Toka 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | */ 21 | 22 | package utils; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Collections; 26 | import java.util.HashMap; 27 | import java.util.Hashtable; 28 | import java.util.Map.Entry; 29 | 30 | import org.apache.commons.math3.stat.Frequency; 31 | import org.joda.time.DateTime; 32 | import org.joda.time.Seconds; 33 | import main.SketchData; 34 | 35 | public class Track { 36 | 37 | private int interval; 38 | private String tag; 39 | private DateTime startDate; 40 | private DateTime endDate; 41 | private boolean visible; 42 | public SketchData data; 43 | 44 | public boolean requiresLeftMap = false; 45 | public boolean requiresRightMap = false; 46 | 47 | private ArrayList trackPoints = new ArrayList(); 48 | private ArrayList trackProperties = new ArrayList(); 49 | 50 | public ArrayList temp = new ArrayList(); 51 | 52 | public void addPoint(PointRecord point) { 53 | this.trackPoints.add(point); 54 | HashMap props = point.getProperties(); 55 | for (Entry entry : props.entrySet()) { 56 | String property = entry.getKey(); 57 | if (!trackProperties.contains(property)) { 58 | this.trackProperties.add(property); 59 | } 60 | } 61 | } 62 | 63 | public ArrayList getPoints() { 64 | return this.trackPoints; 65 | } 66 | 67 | public ArrayList getProperties() { 68 | return this.trackProperties; 69 | } 70 | 71 | public void setStartDate(DateTime d) { 72 | this.startDate = d; 73 | } 74 | 75 | public DateTime getStartDate() { 76 | return this.startDate; 77 | } 78 | 79 | public void setEndDate(DateTime d) { 80 | this.endDate = d; 81 | } 82 | 83 | public DateTime getEndDate() { 84 | return this.endDate; 85 | } 86 | 87 | public void setInterval(int i) { 88 | this.interval = i; 89 | } 90 | 91 | public int getInterval() { 92 | return this.interval; 93 | } 94 | 95 | public void setTag(String t) { 96 | this.tag = t; 97 | } 98 | 99 | public String getTag() { 100 | return this.tag; 101 | } 102 | 103 | public void setVisibility(boolean b) { 104 | this.visible = b; 105 | } 106 | 107 | public boolean getVisibility() { 108 | return this.visible; 109 | } 110 | 111 | // get_gilter_times by Kin (Nathan) Chan 112 | public Hashtable> get_filter_times() { 113 | // ArrayList temp_times = new ArrayList(); 114 | Hashtable> temp_hash = new Hashtable>(); 115 | for (PointRecord point1 : trackPoints) { 116 | if (temp_hash.containsKey(point1.getYear())) { 117 | ArrayList temp_times = temp_hash.get(point1.getYear()); 118 | int temp_month = point1.getMonth(); 119 | if (!temp_times.contains(temp_month)) { 120 | temp_times.add(temp_month); 121 | Collections.sort(temp_times); 122 | temp_hash.replace(point1.getYear(), temp_times); 123 | } 124 | 125 | } else { 126 | temp_hash.put(point1.getYear(), new ArrayList(point1.getMonth())); 127 | } 128 | } 129 | return temp_hash; 130 | } 131 | 132 | public ArrayList gettheTimes() { 133 | for (PointRecord point1 : trackPoints) { 134 | DateTime temptime = point1.getTime(); 135 | temp.add(temptime); 136 | } 137 | 138 | return temp; 139 | 140 | } 141 | 142 | public void calculateTimes() { 143 | 144 | ArrayList col = new ArrayList(); 145 | Frequency f = new Frequency(); 146 | 147 | for (PointRecord point : trackPoints) { 148 | DateTime time = point.getTime(); 149 | col.add(time); 150 | } 151 | 152 | Collections.sort(col); 153 | setStartDate(Collections.min(col)); 154 | setEndDate(Collections.max(col)); 155 | 156 | for (int i = 0; i < col.size() - 1; i++) { 157 | // round up to nearest whole minute 158 | long seconds = Seconds.secondsBetween(col.get(i), col.get(i + 1)).getSeconds(); 159 | long minutes = (long) Math.round((float) seconds / 60); 160 | 161 | f.addValue(minutes); 162 | } 163 | 164 | Long intervalLong = (Long) f.getMode().get(0); 165 | Integer interval = intervalLong != null ? intervalLong.intValue() : null; 166 | 167 | this.setInterval(interval); 168 | } 169 | 170 | public void checkEdgeOfMap() { 171 | boolean closeToRightEdge = false; 172 | boolean pastRightEdge = false; 173 | boolean closeToLeftEdge = false; 174 | boolean pastLeftEdge = false; 175 | float lonCentroid = 0; 176 | 177 | // check if close to edge 178 | for (PointRecord point : trackPoints) { 179 | float y = point.getLocation().y; 180 | 181 | if(y > 175) closeToRightEdge = true; 182 | if(y > 180) pastRightEdge = true; 183 | if(y < -175) closeToLeftEdge = true; 184 | if(y < -180) pastLeftEdge = true; 185 | 186 | lonCentroid += y; 187 | } 188 | lonCentroid /= trackPoints.size(); 189 | 190 | // if close to edge 191 | if((closeToLeftEdge && closeToRightEdge) || pastLeftEdge || pastRightEdge) { 192 | if(lonCentroid > 0) { 193 | requiresRightMap = true; 194 | } 195 | else { 196 | requiresLeftMap = true; 197 | } 198 | 199 | // adjust points 200 | if(closeToLeftEdge && closeToRightEdge) 201 | for (PointRecord point : trackPoints) { 202 | if(lonCentroid > 0) { 203 | point.adjustNegativeLongitudes(); 204 | } 205 | else { 206 | point.adjustPositiveLongitudes(); 207 | } 208 | } 209 | } 210 | } 211 | 212 | } 213 | --------------------------------------------------------------------------------