From fbcbf3e1d70cf86efe68fe14ab23e235f864543c Mon Sep 17 00:00:00 2001 From: Patrick Kuo Date: Wed, 7 Dec 2016 09:55:16 +0000 Subject: [PATCH] Network view improvement (#19) Changes : *Show other nodes on network map. *Enabled zooming and panning on the map. *Scroll the node label to the centre of the screen when clicking on the node info list on the right hand-side of the screen. *Draw line and fire bullets between nodes according to incoming transactions. *Higher resolution map. --- .../main/kotlin/net/corda/explorer/Main.kt | 8 +- .../net/corda/explorer/views/GuiUtilities.kt | 3 + .../net/corda/explorer/views/Network.kt | 224 +++++++++++++----- .../net/corda/explorer/css/corda.css | 17 ++ .../corda/explorer/images/WorldMapSquare.png | Bin 480246 -> 574834 bytes .../net/corda/explorer/views/Network.fxml | 16 +- 6 files changed, 205 insertions(+), 63 deletions(-) diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/Main.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/Main.kt index 16f7bd3a5a..6d78a66cb7 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/Main.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/Main.kt @@ -107,10 +107,10 @@ fun main(args: Array) { driver(portAllocation = portAllocation) { val user = User("user1", "test", permissions = setOf(startFlowPermission())) // TODO : Supported flow should be exposed somehow from the node instead of set of ServiceInfo. - val notary = startNode("Notary", advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))) - val alice = startNode("Alice", rpcUsers = arrayListOf(user), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash")))) - val bob = startNode("Bob", rpcUsers = arrayListOf(user), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash")))) - val issuer = startNode("Royal Mint", rpcUsers = arrayListOf(user), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash")))) + val notary = startNode("Notary", advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)), customOverrides = mapOf("nearestCity" to "Zurich")) + val alice = startNode("Alice", rpcUsers = arrayListOf(user), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash"))), customOverrides = mapOf("nearestCity" to "Paris")) + val bob = startNode("Bob", rpcUsers = arrayListOf(user), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash"))), customOverrides = mapOf("nearestCity" to "Frankfurt")) + val issuer = startNode("Royal Mint", rpcUsers = arrayListOf(user), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash"))), customOverrides = mapOf("nearestCity" to "London")) val notaryNode = notary.get() val aliceNode = alice.get() diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/GuiUtilities.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/GuiUtilities.kt index 6e848ae751..69c2350346 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/GuiUtilities.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/GuiUtilities.kt @@ -81,3 +81,6 @@ fun EventTarget.copyableLabel(value: ObservableValue? = null, op: (TextF } inline fun View.getModel(): M = Models.get(M::class, this.javaClass.kotlin) + +// Cartesian product of 2 collections. +fun Collection.cross(other: Collection) = this.flatMap { a -> other.map { b -> a to b } } diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt index 12a6b9cb09..699a89b996 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt @@ -2,99 +2,213 @@ package net.corda.explorer.views import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView +import javafx.animation.FadeTransition +import javafx.animation.TranslateTransition import javafx.beans.binding.Bindings import javafx.beans.property.SimpleObjectProperty -import javafx.scene.Node +import javafx.collections.FXCollections +import javafx.geometry.Bounds +import javafx.geometry.Point2D import javafx.scene.Parent +import javafx.scene.control.Button import javafx.scene.control.ContentDisplay import javafx.scene.control.Label import javafx.scene.control.ScrollPane +import javafx.scene.image.ImageView import javafx.scene.layout.BorderPane import javafx.scene.layout.Pane import javafx.scene.layout.VBox +import javafx.scene.shape.Circle +import javafx.scene.shape.Line import javafx.scene.text.Font import javafx.scene.text.FontWeight -import net.corda.client.fxutils.map -import net.corda.client.model.NetworkIdentityModel -import net.corda.client.model.observableList -import net.corda.client.model.observableValue +import javafx.util.Duration +import net.corda.client.fxutils.* +import net.corda.client.model.* +import net.corda.core.contracts.ContractState +import net.corda.core.crypto.Party import net.corda.core.node.NodeInfo import net.corda.explorer.model.CordaView import tornadofx.* -// TODO : Construct a node map using node info and display them on a world map. -// TODO : Allow user to see transactions between nodes on a world map. class Network : CordaView() { override val root by fxml() override val icon = FontAwesomeIcon.GLOBE - // Inject data. val myIdentity by observableValue(NetworkIdentityModel::myIdentity) val notaries by observableList(NetworkIdentityModel::notaries) val peers by observableList(NetworkIdentityModel::parties) - - // Components + val transactions by observableList(GatheredTransactionDataModel::partiallyResolvedTransactions) + // UI components private val myIdentityPane by fxid() private val notaryList by fxid() private val peerList by fxid() private val mapScrollPane by fxid() private val mapPane by fxid() + private val mapImageView by fxid() + private val zoomInButton by fxid