Akash Vishwakarma
Akash Vishwakarma

Reputation: 177

Unable to call function Network from vis node module in F#

I'm using vis.js dependency in my Fable-F# project and want to call network function for visualization to display networks. How can I pass the JSON data from F# to Network function?

F# code for importing the module

open Fable.Import.React
open Fable.Helpers
open Fable.Helpers.React
open Fable.Helpers.React.Props
open Fable.Core
open Fable.Core.JsInterop
open Fable.Import
open Fable.Import.Browser

    [<Import("default", "vis")>]
    let Network (we: React.event)  = jsNative
    let destination = Browser.document.getElementById "app"
    let response = Network destination  JsonData options

Vis.js node module code which takes three parameters Github

  function Network(container, data, options) {
  if (!(this instanceof Network)) {
    throw new SyntaxError('Constructor must be called with the new operator');
  }

  // set constant values
  this.options = {};
  this.defaultOptions = {
    locale: 'en',
    locales: locales,
    clickToUse: false

Graph using JS and HTML Github for reference

Upvotes: 2

Views: 310

Answers (1)

Maxime Mangel
Maxime Mangel

Reputation: 1996

In order to use the vis library you can follow this steps:

  1. Go to @types/vis npm package
  2. Follow the link and copy the content of the index.d.ts file
  3. Paste it to the left panel of ts2fable online
  4. You can then copy and save the generated definition file in your project (example in vis.fs). You will have (at the moment of writing this anwser) 4 errors. You can comments the corresponding lines.

For me:

// At the top of the file
type MomentInput = Moment.MomentInput
type MomentFormatSpecification = Moment.MomentFormatSpecification
type Moment = Moment.Moment

// In the middle of it
type [<AllowNullLiteral>] TimelineStatic =
    interface end
  1. Now you can use the vis.js library

Here is the simple network code ported:

// Fable demo ported from http://visjs.org/examples/network/basicUsage.html
module Client

open Fable.Core
open Fable.Core.JsInterop
open Fable.Import

// We import the vis.css style
importSideEffects "vis/dist/vis.css"

// We create an access to the vis library
// We could put it under vis.fs file but it's easier to access it from here
[<Import("*", "vis")>]
let visLib : vis.IExports = jsNative

// Helper to make the code easier to read
let createNode id label =
    jsOptions<vis.Node>(fun o ->
        o.id <- Some !^id
        o.label <- Some label
    )

// Helper to make the code easier to read
let createEdge from ``to`` =
    jsOptions<vis.Edge>(fun o ->
        o.from <- Some !^from
        o.``to`` <- Some !^``to``
    )

// If I was using this library I would probably write some helpers to have something like:
// Node.empty
// |> Node.withId 1
// |> Node.withLabel "My label"
// |> ...
// Like that the code is cleaner and more flexible

// From here this is almost a 1 to 1 with the JavaScript code
let nodes =
    ResizeArray([|
        createNode 1. "Node 1"
        createNode 2. "Node 2"
        createNode 3. "Node 3"
        createNode 4. "Node 4"
        createNode 5. "Node 5"
    |])
    |> visLib.DataSet.Create

let edges =
    ResizeArray([|
        createEdge 1. 3.
        createEdge 1. 2.
        createEdge 2. 4.
        createEdge 2. 5.
        createEdge 3. 3.
    |])
    |> visLib.DataSet.Create

let datas =
    jsOptions<vis.Data>(fun o ->
        o.nodes <- Some (U2.Case2 nodes)
        o.edges <- Some (U2.Case2 edges)
    )

let container = Browser.document.getElementById("elmish-app");

// Because we don't have any option to pass, we need to give an empty object 
// otherwise vis.js failed at runtime
let network = visLib.Network.Create(container, datas, createEmpty)

Upvotes: 1

Related Questions