hyper-vis

A Opal Ruby wrapper for Vis.js with a Ruby-Hyperloop Component. Implements the complete API for:

Includes vis.js version 4.21.0

Demo

Reactive hyper-vis in action:

Reactivity Demo

Quality

Build Status GitHub issues Percentage of issues still open Average time to resolve an issue Pending Pull-Requests

Tests

Finished in 2 minutes 39.7 seconds (files took 3.18 seconds to load)
132 examples, 0 failures, 15 pending

To run Tests

Clone repo, then:

bundle update
cd spec/test_app
bundle update
cd ../..
bundle exec rspec

Installation

for a Rails app:

gem 'hyper-vis'

and bundle update.

hyper-vis depends on hyper-component from Ruby-Hyperloop but can be used without it.

vis.js is automatically imported for Ruby-Hyperloop. If you get vis.js with webpacker, you may need to cancel the import in your config/intializers/hyperloop.rb

  config.cancel_import 'vis/source/vis.js'

The wrapper expects a global vis (not Vis) to be availabe in javascript. For Vis to function as expected the stylesheets must be included. For a Rails app, the asset path is automatically added. In your application.css add:

  *= require vis.css

For other frameworks vis.js, stylesheets and images are available in the gems lib/vis/source/ directory.

Usage

The wrapper follows vis 1 to 1, conforming to ruby standards, instead of setSize in javascript, you would use set_size. Also see specs in the specs directory for usage or the vis documentation (linked above). All arguments or return values are 'rubyfied' as much as possible, so you can just use ruby.

The Vis part

dataset = Vis::DataSet.new([{id: 1, name: 'foo'}, {id: 2, name: 'bar'}, {id: 3, name: 'pub'}])
edge_dataset = Vis::DataSet.new([{from: 1, to: 2}, {from: 2, to: 3}])
dom_node = Vis::Network.test_container
net = Vis::Network.new(dom_node, {nodes: dataset, edges: edge_dataset})
xy = net.canvas_to_dom({x: 10, y: 10})

The Component part

The Components takes care about all the things necessary to make Vis.js play nice with React. The Components also provide a helper to access the document: document.

Vis::Network::Mixin

Vis::Network can be used within the render_with_dom_node.

class MyVisNetworkComponent
  include Hyperloop::Vis::Network::Mixin

  # the component automatically calls the render_with_dom_node block every
  # time new data or options are received

  # however
  # setting automatic_refresh false turns that off ...
  # (default is true, so this is optional):
  automatic_refresh false

  # ... and with automatic_refresh false refresh can
  # be handled in the before_receive_props callback
  # for example (this is also optional):
  before_receive_props do |new_props|
    # data can be accessed using the helper vis_data
    if new_props[:vis_data] != vis_data
      @net.set_data(new_props[:vis_data])
    end
  end

  render_with_dom_node do |dom_node, data, options|
    # its important to use the data as passed in as 'data' argument
    # to get the latests passed data for each new render
    @net = Vis::Network.new(dom_node, data, options)

    # data is also atomatically saved and available using the helper
    vis_data

    # example of using the document helper
    canvas = document.JS.querySelector('canvas')
  end
end

class AOuterComponent < Hyperloop::Component
  render do
    received_data = []

    # example of using a callback in the options
    options = { manipulation: {
        edit_node: proc { |node_data, callback| received_data << node_data }
      }}

    # initialize a dataset
    data = Vis::DataSet.new([{id: 1, name: 'foo'}, {id: 2, name: 'bar'}, {id: 3, name: 'pub'}])

    # call the component
    DIV { MyVisNetworkComponent(vis_data: data, otions: options)}
  end
end

Vis::Graph3d::Mixin

Works the same as Vis::Network::Mixin

Vis::Timeline::Mixin

Similar to Vis::Network, mostly params and helpers are different:

class MyVisTimelineComponent
  include Hyperloop::Vis::Timeline::Mixin

  # the component automatically calls the render_with_dom_node block every
  # time new data or options are received

  # however
  # setting automatic_refresh false turns that off ...
  # (default is true, so this is optional):
  automatic_refresh false

  # ... and with automatic_refresh false refresh can
  # be handled in the before_receive_props callback
  # for example (this is also optional):
  before_receive_props do |new_props|
    # data can be accessed using the helpers:
    items
    groups
    options
  end

  render_with_dom_node do |dom_node, items, groups, options|
    # its important to use the data as passed in as 'data' argument
    # to get the latests passed data for each new render
    @net = Vis::Timeline.new(dom_node, items, groups, options)

    # data is also atomatically saved and available using the helpers
    items
    groups
    options
  end
end

class AOuterComponent < Hyperloop::Component
  render do
    options = { align: 'left' }

    # initialize a dataset
    data = Vis::DataSet.new([
            {id: 1, content: 'item 1', start: '2013-04-20'},
            {id: 2, content: 'item 2', start: '2013-04-14'},
            {id: 3, content: 'item 3', start: '2013-04-18'},
            {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
            {id: 5, content: 'item 5', start: '2013-04-25'},
            {id: 6, content: 'item 6', start: '2013-04-27'}
          ])

    # call the component
    DIV { MyVisTimelineComponent(items: data, otions: options)}
  end
end

Vis::Graph2d::Mixin

Works the same as Vis::Timeline::Mixin