Browse Source

split up read and write charts and added cache efficiency chart
(because we will add further read/write-specific stats like total number of files read/written, bytes encrypted/decrypted, etc)

Sebastian Stenzel 5 years ago
parent
commit
9c034f3be6

+ 24 - 0
main/commons/src/main/java/org/cryptomator/common/vaults/VaultStats.java

@@ -2,9 +2,12 @@ package org.cryptomator.common.vaults;
 
 import javafx.application.Platform;
 import javafx.beans.Observable;
+import javafx.beans.property.DoubleProperty;
 import javafx.beans.property.LongProperty;
 import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleDoubleProperty;
 import javafx.beans.property.SimpleLongProperty;
+import javafx.beans.value.ObservableValue;
 import javafx.concurrent.ScheduledService;
 import javafx.concurrent.Task;
 import javafx.util.Duration;
@@ -28,6 +31,7 @@ public class VaultStats {
 	private final ScheduledService<Optional<CryptoFileSystemStats>> updateService;
 	private final LongProperty bytesPerSecondRead = new SimpleLongProperty();
 	private final LongProperty bytesPerSecondWritten = new SimpleLongProperty();
+	private final DoubleProperty cacheHitRate = new SimpleDoubleProperty();
 
 	@Inject
 	VaultStats(AtomicReference<CryptoFileSystem> fs, ObjectProperty<VaultState> state, ExecutorService executor) {
@@ -55,6 +59,17 @@ public class VaultStats {
 		assert Platform.isFxApplicationThread();
 		bytesPerSecondRead.set(stats.map(CryptoFileSystemStats::pollBytesRead).orElse(0l));
 		bytesPerSecondWritten.set(stats.map(CryptoFileSystemStats::pollBytesWritten).orElse(0l));
+		cacheHitRate.set(stats.map(this::getCacheHitRate).orElse(0.0));
+	}
+	
+	private double getCacheHitRate(CryptoFileSystemStats stats) {
+		long accesses = stats.pollChunkCacheAccesses();
+		long hits = stats.pollChunkCacheHits();
+		if (accesses == 0) {
+			return 0.0;
+		} else {
+			return hits / (double) accesses;
+		}
 	}
 
 	private class UpdateStatsService extends ScheduledService<Optional<CryptoFileSystemStats>> {
@@ -94,4 +109,13 @@ public class VaultStats {
 	public long getBytesPerSecondWritten() {
 		return bytesPerSecondWritten.get();
 	}
+
+	public DoubleProperty cacheHitRateProperty() {
+		return cacheHitRate;
+	}
+
+	public double getCacheHitRate() {
+		return cacheHitRate.get();
+	}
+	
 }

+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java

@@ -28,7 +28,7 @@ public enum FxmlFile {
 	UNLOCK_INVALID_MOUNT_POINT("/fxml/unlock_invalid_mount_point.fxml"), //
 	UNLOCK_SUCCESS("/fxml/unlock_success.fxml"), //
 	VAULT_OPTIONS("/fxml/vault_options.fxml"), //
-	VAULT_STATISTICS("/fxml/vault_statistics.fxml"), //
+	VAULT_STATISTICS("/fxml/stats.fxml"), //
 	WRONGFILEALERT("/fxml/wrongfilealert.fxml");
 
 	private final String ressourcePathString;

+ 20 - 0
main/ui/src/main/java/org/cryptomator/ui/common/WeakBindings.java

@@ -1,5 +1,6 @@
 package org.cryptomator.ui.common;
 
+import javafx.beans.binding.DoubleBinding;
 import javafx.beans.binding.LongBinding;
 import javafx.beans.binding.StringBinding;
 import javafx.beans.value.ObservableObjectValue;
@@ -50,4 +51,23 @@ public final class WeakBindings {
 		};
 	}
 
+	/**
+	 * Create a new DoubleBinding that listens to changes from the given observable without being strongly referenced by it.
+	 *
+	 * @param observable The observable
+	 * @return a DoubleBinding weakly referenced from the given observable
+	 */
+	public static DoubleBinding bindDouble(ObservableValue<Number> observable) {
+		return new DoubleBinding() {
+			{
+				bind(observable);
+			}
+
+			@Override
+			protected double computeValue() {
+				return observable.getValue().doubleValue();
+			}
+		};
+	}
+
 }

+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java

@@ -20,7 +20,7 @@ import org.cryptomator.ui.common.StageFactory;
 import org.cryptomator.ui.migration.MigrationComponent;
 import org.cryptomator.ui.removevault.RemoveVaultComponent;
 import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
-import org.cryptomator.ui.vaultstatistics.VaultStatisticsComponent;
+import org.cryptomator.ui.stats.VaultStatisticsComponent;
 import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent;
 
 import javax.inject.Provider;

+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java

@@ -6,7 +6,7 @@ import javafx.fxml.FXML;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.common.VaultService;
-import org.cryptomator.ui.vaultstatistics.VaultStatisticsComponent;
+import org.cryptomator.ui.stats.VaultStatisticsComponent;
 
 import javax.inject.Inject;
 

+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/vaultstatistics/VaultStatisticsComponent.java

@@ -1,4 +1,4 @@
-package org.cryptomator.ui.vaultstatistics;
+package org.cryptomator.ui.stats;
 
 import dagger.BindsInstance;
 import dagger.Lazy;

+ 63 - 25
main/ui/src/main/java/org/cryptomator/ui/vaultstatistics/VaultStatisticsController.java

@@ -1,13 +1,17 @@
-package org.cryptomator.ui.vaultstatistics;
+package org.cryptomator.ui.stats;
 
 import javafx.animation.Animation;
 import javafx.animation.KeyFrame;
 import javafx.animation.Timeline;
+import javafx.beans.binding.Bindings;
+import javafx.beans.binding.DoubleBinding;
 import javafx.beans.binding.LongBinding;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
 import javafx.fxml.FXML;
+import javafx.scene.chart.AreaChart;
 import javafx.scene.chart.LineChart;
+import javafx.scene.chart.NumberAxis;
 import javafx.scene.chart.XYChart.Data;
 import javafx.scene.chart.XYChart.Series;
 import javafx.stage.Stage;
@@ -18,13 +22,14 @@ import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.common.WeakBindings;
 
 import javax.inject.Inject;
+import java.util.Arrays;
 import java.util.ResourceBundle;
 
 @VaultStatisticsScoped
 public class VaultStatisticsController implements FxController {
 
-	private static final int IO_SAMPLING_STEPS = 100;
-	private static final double IO_SAMPLING_INTERVAL = 0.5;
+	private static final int IO_SAMPLING_STEPS = 30;
+	private static final double IO_SAMPLING_INTERVAL = 1;
 
 	private final VaultStats stats;
 	private final Series<Number, Number> readData;
@@ -32,19 +37,27 @@ public class VaultStatisticsController implements FxController {
 	private final Timeline ioAnimation;
 	private final LongBinding bpsRead;
 	private final LongBinding bpsWritten;
+	private final DoubleBinding cacheHitRate;
+	private final DoubleBinding cacheHitDregrees;
+	private final DoubleBinding cacheHitPercentage;
 
-	public LineChart<Number, Number> lineGraph;
+	public AreaChart<Number, Number> readChart;
+	public AreaChart<Number, Number> writeChart;
+	public NumberAxis readChartXAxis;
+	public NumberAxis readChartYAxis;
+	public NumberAxis writeChartXAxis;
+	public NumberAxis writeChartYAxis;
 
 	@Inject
 	public VaultStatisticsController(@VaultStatisticsWindow Stage window, @VaultStatisticsWindow Vault vault, ResourceBundle resourceBundle) {
 		this.stats = vault.getStats();
-		this.bpsRead = WeakBindings.bindLong(stats.bytesPerSecondReadProperty());
-		this.bpsWritten = WeakBindings.bindLong(stats.bytesPerSecondWrittenProperty());
-
 		this.readData = new Series<>();
-		readData.setName(resourceBundle.getString("vaultstatistics.readDataLabel"));
 		this.writeData = new Series<>();
-		writeData.setName(resourceBundle.getString("vaultstatistics.writtenDataLabel"));
+		this.bpsRead = WeakBindings.bindLong(stats.bytesPerSecondReadProperty());
+		this.bpsWritten = WeakBindings.bindLong(stats.bytesPerSecondWrittenProperty());
+		this.cacheHitRate = WeakBindings.bindDouble(stats.cacheHitRateProperty());
+		this.cacheHitDregrees = cacheHitRate.multiply(-270);
+		this.cacheHitPercentage = cacheHitRate.multiply(100);
 
 		this.ioAnimation = new Timeline(); //TODO Research better timer
 		ioAnimation.getKeyFrames().add(new KeyFrame(Duration.seconds(IO_SAMPLING_INTERVAL), new IoSamplingAnimationHandler(readData, writeData)));
@@ -60,14 +73,18 @@ public class VaultStatisticsController implements FxController {
 
 	@FXML
 	public void initialize() {
-		lineGraph.getData().addAll(readData, writeData);
+		readChart.getData().addAll(readData);
+		writeChart.getData().addAll(writeData);
 	}
 
 	private class IoSamplingAnimationHandler implements EventHandler<ActionEvent> {
 
 		private static final double BYTES_TO_MEGABYTES_FACTOR = 1.0 / IO_SAMPLING_INTERVAL / 1024.0 / 1024.0;
+		
+		private long step = IO_SAMPLING_STEPS;
 		private final Series<Number, Number> decryptedBytesRead;
 		private final Series<Number, Number> encryptedBytesWrite;
+		private final long[] maxBuf = new long[IO_SAMPLING_STEPS];
 
 		public IoSamplingAnimationHandler(Series<Number, Number> readData, Series<Number, Number> writeData) {
 			this.decryptedBytesRead = readData;
@@ -82,23 +99,28 @@ public class VaultStatisticsController implements FxController {
 
 		@Override
 		public void handle(ActionEvent event) {
-			// move all values one step:
-			for (int i = 0; i < IO_SAMPLING_STEPS - 1; i++) {
-				int j = i + 1;
-				Number tmp = decryptedBytesRead.getData().get(j).getYValue();
-				decryptedBytesRead.getData().get(i).setYValue(tmp);
-
-				tmp = encryptedBytesWrite.getData().get(j).getYValue();
-				encryptedBytesWrite.getData().get(i).setYValue(tmp);
-			}
-
-			// add latest value:
+			final long currentStep = step++;
 			final long decBytes = stats.bytesPerSecondReadProperty().get();
-			final double decMb = decBytes * BYTES_TO_MEGABYTES_FACTOR;
 			final long encBytes = stats.bytesPerSecondWrittenProperty().get();
-			final double encMb = encBytes * BYTES_TO_MEGABYTES_FACTOR;
-			decryptedBytesRead.getData().get(IO_SAMPLING_STEPS - 1).setYValue(decMb);
-			encryptedBytesWrite.getData().get(IO_SAMPLING_STEPS - 1).setYValue(encMb);
+
+			maxBuf[(int) currentStep % IO_SAMPLING_STEPS] = Math.max(decBytes, encBytes);
+			long allTimeMax = Arrays.stream(maxBuf).max().orElse(0l);
+			
+			// remove oldest value:
+			decryptedBytesRead.getData().remove(0);
+			encryptedBytesWrite.getData().remove(0);
+
+			// add latest value:
+			decryptedBytesRead.getData().add(new Data<>(currentStep, decBytes));
+			encryptedBytesWrite.getData().add(new Data<>(currentStep, encBytes));
+			
+			// adjust ranges:
+			readChartXAxis.setLowerBound(currentStep - IO_SAMPLING_STEPS);
+			readChartXAxis.setUpperBound(currentStep);
+			readChartYAxis.setUpperBound(allTimeMax);
+			writeChartXAxis.setLowerBound(currentStep - IO_SAMPLING_STEPS);
+			writeChartXAxis.setUpperBound(currentStep);
+			writeChartYAxis.setUpperBound(allTimeMax);
 		}
 	}
 
@@ -119,4 +141,20 @@ public class VaultStatisticsController implements FxController {
 	public long getBpsWritten() {
 		return bpsWritten.get();
 	}
+
+	public DoubleBinding cacheHitPercentageProperty() {
+		return cacheHitPercentage;
+	}
+
+	public double getCacheHitPercentage() {
+		return cacheHitPercentage.get();
+	}
+
+	public DoubleBinding cacheHitDregreesProperty() {
+		return cacheHitDregrees;
+	}
+
+	public double getCacheHitDregrees() {
+		return cacheHitDregrees.get();
+	}
 }

+ 3 - 3
main/ui/src/main/java/org/cryptomator/ui/vaultstatistics/VaultStatisticsModule.java

@@ -1,4 +1,4 @@
-package org.cryptomator.ui.vaultstatistics;
+package org.cryptomator.ui.stats;
 
 import dagger.Binds;
 import dagger.Module;
@@ -38,7 +38,7 @@ abstract class VaultStatisticsModule {
 	@VaultStatisticsScoped
 	static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle, @VaultStatisticsWindow Vault vault) {
 		Stage stage = factory.create();
-		stage.setTitle(String.format(resourceBundle.getString("vaultstatistics.title"), vault.getDisplayableName()));
+		stage.setTitle(String.format(resourceBundle.getString("stats.title"), vault.getDisplayableName()));
 		stage.setResizable(false);
 		var weakStage = new WeakReference<>(stage);
 		vault.stateProperty().addListener(new ChangeListener<>() {
@@ -60,7 +60,7 @@ abstract class VaultStatisticsModule {
 	@FxmlScene(FxmlFile.VAULT_STATISTICS)
 	@VaultStatisticsScoped
 	static Scene provideVaultStatisticsScene(@VaultStatisticsWindow FXMLLoaderFactory fxmlLoaders) {
-		return fxmlLoaders.createScene("/fxml/vault_statistics.fxml");
+		return fxmlLoaders.createScene("/fxml/stats.fxml");
 	}
 
 	// ------------------

+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/vaultstatistics/VaultStatisticsScoped.java

@@ -1,4 +1,4 @@
-package org.cryptomator.ui.vaultstatistics;
+package org.cryptomator.ui.stats;
 
 import javax.inject.Scope;
 import java.lang.annotation.Documented;

+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/vaultstatistics/VaultStatisticsWindow.java

@@ -1,4 +1,4 @@
-package org.cryptomator.ui.vaultstatistics;
+package org.cryptomator.ui.stats;
 
 import javax.inject.Qualifier;
 import java.lang.annotation.Documented;

+ 34 - 41
main/ui/src/main/resources/css/dark_theme.css

@@ -874,59 +874,52 @@
  * I/O Statistics                                                              *
  *                                                                             *
  ******************************************************************************/
-.chart {
-	-fx-padding: 10px;
-}
 
-.chart-plot-background {
-	-fx-background-color: MAIN_BG;
-	-fx-padding: 20px;
+.cache-arc-background {
+	-fx-fill: transparent;
+	-fx-stroke: MUTED_BG;
+	-fx-stroke-type: centered;
+	-fx-stroke-width: 12;
+	-fx-stroke-line-cap: butt;
 }
 
-/* content */
+.cache-arc-foreground {
+	-fx-fill: transparent;
+	-fx-stroke: PRIMARY;
+	-fx-stroke-type: centered;
+	-fx-stroke-width: 12;
+	-fx-stroke-line-cap: butt;
+}
 
-.chart-content {
+.chart.io-stats {
 	-fx-padding: 10px;
-	-fx-text-fill: TEXT_FILL;
-	-fx-tick-label-fill: GRAY_3;
-	-fx-minor-tick-visible: false
-}
-.chart-horizontal-grid-lines {
-	-fx-stroke: PRIMARY_L2;
+	-fx-horizontal-grid-lines-visible: false;
+	-fx-horizontal-zero-line-visible: false;
+	-fx-vertical-grid-lines-visible: false;
+	-fx-vertical-zero-line-visible: false;
 }
-.chart-vertical-zero-line,
-.chart-horizontal-zero-line {
-	-fx-stroke: PRIMARY_L2;
+
+.axis.io-stats {
+	-fx-tick-mark-visible: false;
+	-fx-minor-tick-visible: false;
+	-fx-tick-labels-visible: false;
 }
-.chart-series-line {
-	-fx-stroke-width: 2px;
+
+.chart-plot-background {
+	-fx-background-color: transparent;
 }
+
+.chart-vertical-zero-line,
+.chart-horizontal-zero-line,
 .chart-alternative-row-fill {
-	-fx-fill: GRAY_3;
 	-fx-stroke: transparent;
 	-fx-stroke-width: 0;
 }
-.axis {
-	-fx-tick-label-fill: TEXT_FILL;
-	-fx-tick-length: 20;
-	-fx-minor-tick-length: 10;
-}
-.axis-label {
-	-fx-text-fill: TEXT_FILL;
-}
-.default-color0.chart-series-line { -fx-stroke: PRIMARY; }
-.default-color1.chart-series-line { -fx-stroke: RED_5 ; }
-
-/* legend */
 
-.chart-legend {
-	-fx-text-fill: TEXT_FILL;
-	-fx-background-color: transparent;
-	-fx-padding: 0.4em;
+.default-color0.chart-series-area-line {
+	-fx-stroke: PRIMARY;
 }
-.chart-line-symbol {
-	-fx-background-radius: 5px;
-	-fx-padding: 5px;
+.default-color0.chart-series-area-fill {
+	-fx-fill: linear-gradient(to bottom, PRIMARY, transparent);
+	-fx-stroke: transparent;
 }
-.default-color0.chart-line-symbol { -fx-background-color: PRIMARY; }
-.default-color1.chart-line-symbol { -fx-background-color: RED_5; }

+ 38 - 34
main/ui/src/main/resources/css/light_theme.css

@@ -884,48 +884,52 @@
 
 /* content */
 
-.chart-content {
-	-fx-padding: 10px;
-	-fx-text-fill: TEXT_FILL;
-	-fx-tick-label-fill: GRAY_3;
-	-fx-minor-tick-visible: false
+
+.cache-arc-background {
+	-fx-fill: transparent;
+	-fx-stroke: MUTED_BG;
+	-fx-stroke-type: centered;
+	-fx-stroke-width: 12;
+	-fx-stroke-line-cap: butt;
 }
-.chart-horizontal-grid-lines {
-	-fx-stroke: PRIMARY_D2;
+
+.cache-arc-foreground {
+	-fx-fill: transparent;
+	-fx-stroke: PRIMARY;
+	-fx-stroke-type: centered;
+	-fx-stroke-width: 12;
+	-fx-stroke-line-cap: butt;
 }
-.chart-vertical-zero-line,
-.chart-horizontal-zero-line {
-	-fx-stroke: PRIMARY_D2;
+
+.chart.io-stats {
+	-fx-padding: 10px;
+	-fx-horizontal-grid-lines-visible: false;
+	-fx-horizontal-zero-line-visible: false;
+	-fx-vertical-grid-lines-visible: false;
+	-fx-vertical-zero-line-visible: false;
 }
-.chart-series-line {
-	-fx-stroke-width: 2px;
+
+.axis.io-stats {
+	-fx-tick-mark-visible: false;
+	-fx-minor-tick-visible: false;
+	-fx-tick-labels-visible: false;
 }
+
+.chart-plot-background {
+	-fx-background-color: transparent;
+}
+
+.chart-vertical-zero-line,
+.chart-horizontal-zero-line,
 .chart-alternative-row-fill {
-	-fx-fill: GRAY_8;
 	-fx-stroke: transparent;
 	-fx-stroke-width: 0;
 }
-.axis {
-	-fx-tick-label-fill: TEXT_FILL;
-	-fx-tick-length: 20;
-	-fx-minor-tick-length: 10;
-}
-.axis-label {
-	-fx-text-fill: TEXT_FILL;
-}
-.default-color0.chart-series-line { -fx-stroke: PRIMARY; }
-.default-color1.chart-series-line { -fx-stroke: RED_5 ; }
-
-/* legend */
 
-.chart-legend {
-	-fx-text-fill: TEXT_FILL;
-	-fx-background-color: transparent;
-	-fx-padding: 0.4em;
+.default-color0.chart-series-area-line {
+	-fx-stroke: PRIMARY;
 }
-.chart-line-symbol {
-	-fx-background-radius: 5px;
-	-fx-padding: 5px;
+.default-color0.chart-series-area-fill {
+	-fx-fill: linear-gradient(to bottom, PRIMARY, transparent);
+	-fx-stroke: transparent;
 }
-.default-color0.chart-line-symbol { -fx-background-color: PRIMARY; }
-.default-color1.chart-line-symbol { -fx-background-color: RED_5; }

+ 77 - 0
main/ui/src/main/resources/fxml/stats.fxml

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.chart.AreaChart?>
+<?import javafx.scene.chart.NumberAxis?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.Cursor?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.StackPane?>
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.shape.Arc?>
+<?import org.cryptomator.ui.controls.FormattedLabel?>
+<?import org.cryptomator.ui.controls.ThrougputLabel?>
+<?import javafx.scene.Group?>
+<HBox xmlns="http://javafx.com/javafx"
+	  xmlns:fx="http://javafx.com/fxml"
+	  fx:controller="org.cryptomator.ui.stats.VaultStatisticsController"
+	  prefWidth="600.0" spacing="12">
+	<padding>
+		<Insets topRightBottomLeft="12"/>
+	</padding>
+	
+	<!-- Caching -->
+	<VBox prefWidth="200" prefHeight="200">
+		<StackPane>
+			<Group>
+				<Arc styleClass="cache-arc-background" centerX="100" centerY="100" radiusX="100" radiusY="100" startAngle="225" length="-270"/>
+				<Arc styleClass="cache-arc-foreground" centerX="100" centerY="100" radiusX="100" radiusY="100" startAngle="225" length="${controller.cacheHitDregrees}"/>
+			</Group>
+			<VBox StackPane.alignment="CENTER" alignment="CENTER">
+				<FormattedLabel styleClass="label-large" format="\%1.0f %%" arg1="${controller.cacheHitPercentage}" />
+				<Label text="%stats.cacheHitRate" />
+			</VBox>
+		</StackPane>
+	</VBox>
+
+	<!-- Read -->
+	<VBox prefWidth="200" prefHeight="200">
+		<HBox spacing="12">
+			<Label text="%stats.readDataLabel"/>
+			<ThrougputLabel styleClass="label-large" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps"
+						mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.bpsRead}"/>
+		</HBox>
+		<AreaChart fx:id="readChart" styleClass="io-stats" createSymbols="false" animated="false">
+			<xAxis>
+				<NumberAxis fx:id="readChartXAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="false" side="BOTTOM"/>
+			</xAxis>
+			<yAxis>
+				<NumberAxis fx:id="readChartYAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="true" side="LEFT" tickUnit="Infinity"/>
+			</yAxis>
+			<cursor>
+				<Cursor fx:constant="DEFAULT"/>
+			</cursor>
+		</AreaChart>
+	</VBox>
+
+	<!-- Write -->
+	<VBox prefWidth="200" prefHeight="200">
+		<HBox>
+			<Label text="%stats.writtenDataLabel"/>
+			<ThrougputLabel styleClass="label-large" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps"
+							mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.bpsWritten}"/>
+		</HBox>
+		<AreaChart fx:id="writeChart" styleClass="io-stats" createSymbols="false" animated="false">
+			<xAxis>
+				<NumberAxis fx:id="writeChartXAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="false" side="BOTTOM"/>
+			</xAxis>
+			<yAxis>
+				<NumberAxis fx:id="writeChartYAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="true" side="LEFT" tickUnit="Infinity"/>
+			</yAxis>
+			<cursor>
+				<Cursor fx:constant="DEFAULT"/>
+			</cursor>
+		</AreaChart>
+	</VBox>
+	
+</HBox>

+ 0 - 37
main/ui/src/main/resources/fxml/vault_statistics.fxml

@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<?import javafx.scene.chart.LineChart?>
-<?import javafx.scene.chart.NumberAxis?>
-<?import javafx.scene.control.Label?>
-<?import javafx.scene.Cursor?>
-<?import javafx.scene.layout.HBox?>
-<?import javafx.scene.layout.VBox?>
-<?import org.cryptomator.ui.controls.ThrougputLabel?>
-<VBox xmlns="http://javafx.com/javafx"
-	  xmlns:fx="http://javafx.com/fxml"
-	  fx:controller="org.cryptomator.ui.vaultstatistics.VaultStatisticsController"
-	  prefHeight="400.0" prefWidth="600.0">
-
-	<LineChart fx:id="lineGraph" VBox.vgrow="ALWAYS" createSymbols="false" legendVisible="true" prefHeight="372.0" prefWidth="423.0" visible="true" animated="false"
-			   title="%vaultstatistics.throughputTitle" verticalZeroLineVisible="true" verticalGridLinesVisible="false" horizontalGridLinesVisible="true">
-		<xAxis>
-			<NumberAxis autoRanging="false" lowerBound="0" side="BOTTOM" tickUnit="5" upperBound="100" label="%vaultstatistics.xAxisTimeLabel"/>
-		</xAxis>
-		<yAxis>
-			<NumberAxis autoRanging="true" lowerBound="0" side="LEFT" tickUnit="1024" upperBound="100" label="%vaultstatistics.yAxisThroughputLabel" forceZeroInRange="true"/>
-		</yAxis>
-		<cursor>
-			<Cursor fx:constant="DEFAULT"/>
-		</cursor>
-	</LineChart>
-	<HBox alignment="CENTER_RIGHT" spacing="6">
-		<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondRead"/>
-		<ThrougputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps"
-						mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.bpsRead}"/>
-	</HBox>
-	<HBox alignment="CENTER_RIGHT" spacing="6">
-		<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondWritten"/>
-		<ThrougputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps"
-						mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.bpsWritten}"/>
-	</HBox>
-</VBox>

+ 4 - 6
main/ui/src/main/resources/i18n/strings.properties

@@ -161,12 +161,10 @@ preferences.donationKey.getDonationKey=Get a donation key
 preferences.about=About
 
 # Vault Statistics
-vaultstatistics.title=Statistics for %s
-vaultstatistics.xAxisTimeLabel=Seconds
-vaultstatistics.yAxisThroughputLabel=Throughput in KiB/s
-vaultstatistics.throughputTitle=Read and Writes
-vaultstatistics.readDataLabel=Read Data
-vaultstatistics.writtenDataLabel=Written Data
+stats.title=Statistics for %s
+stats.readDataLabel=Read Data
+stats.writtenDataLabel=Written Data
+stats.cacheHitRate=Cache Hit Rate
 
 # Main Window
 main.closeBtn.tooltip=Close