Coder Social home page Coder Social logo

scala-js-d3's People

Contributors

fdietze avatar fxmouthuy avatar joprice avatar spaced avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

scala-js-d3's Issues

axis as function

In javascript axis as-is can be used as a function.
In scala this is supported by the apply functions.

trait Axis extends js.Any { 
 def apply(selection: Selection[js.Any]): Unit = js.native
 def apply(selection: Transition[js.Any]): Unit = js.native

However this makes it hard to pass an axis as argument to the selection.call() function,
as in e.g. from Simple d3.js Graph

svg
   .append("g")
   .attr("class", "x axis")
   .call(xAxis)

I suggest the following:

trait Axis extends js.Function1[ Selection[js.Any] | Transition[js.Any], Unit] 

Use types for layout.force[...]()

I had a look to the TODO's to support more typed functions, e.g. to created a custom typed layout.Force.
You may encounter issues with mutable typed classes, which you can't make co-variant, such as e.g. Link[Node].
The following approach may help:

@js.native
trait AbstractLink extends js.Object {
  type Node <: forceModule.Node
  var source: Node
  var target: Node
}

@js.native
trait Link[T <: forceModule.Node] extends forceModule.AbstractLink {
  type Node = T
}

@js.native
trait Force[Link <: forceModule.AbstractLink, Node <: forceModule.Node] extends js.Object 

Node trait

I was looking for a better way to create Node instances, i.s.o. ( see example posted in Issue 6)

def apply(id: String): Node = {
      val n = new js.Object().asInstanceOf[Node]
      n.id = id
      n
    }

First, I changed trait forceModule.Node into a class

package forceModule {  . . .

@js.annotation.ScalaJSDefined
class Node extends js.Object {
  var index: Double = 0  // or null.asInstanceOf[Double]
  var x: Double = 0
  var y: Double = 0
  var px: Double = 0
  var py: Double = 0
  var fixed: Boolean = false // or null.asInstanceOf[Boolean]
  var weight: Double = 0
}

 . . . }

So I could change the object creation in the example into:

object ForceLayoutExample extends JSApp { . . .

@js.annotation.ScalaJSDefined
class Node(val id: String) extends forceModule.Node

object Node {
  def apply(id:String): Node = new Node(id)
}

. . . }

While wondering whether it was a good idea to turn forceModule.Node into a class, I realised that Node is not defined as a class in d3.js; actually it is not defined at all. The API accepts or produces an object with the members x, y, etc, without explicitly defining a javascript class for it. This is interesting, because this means that there is not a strict reason to define the trait forceModule.Node as @js.native. This gives more flexibility form a scala perspective. As long as the objects that we pass to the d3.js API have the expected var members, it should be fine.

I'm relatively new into scala-js but I tried the following (complete other approach than above) and it works as well:

package forceModule {  . . .

// no js.native! 
trait Node {
  var index: Double
  var x: Double
  var y: Double
  var px: Double
  var py: Double
  var fixed: Boolean
  var weight: Double
}

import js.annotation.JSExport
@JSExport
class DefaultNode extends Node { // alternatively init the vars to null
  @JSExport var index: Double = 0
  @JSExport var x: Double = 0
  @JSExport var y: Double = 0
  @JSExport var px: Double = 0
  @JSExport var py: Double = 0
  @JSExport var fixed: Boolean = false
  @JSExport var weight: Double = 0
}

. . . }

object ForceLayoutExample extends JSApp { . . .

case class Node(id: String) extends forceModule.DefaultNode

. . . }

I could even define a case class which would be not allowed extending from a js.native trait.

Some food for though ...

svg.line, line.x, line.y

I re-implemented http://bl.ocks.org/d3noob/b3ff6ae1c120eea654b5
To do this I had to apply following changes in svg.scala:

def line[Datum](): Line[Datum] = js.native
    . . .
trait Line[T] extends js.Object {
   . . .
  def x[Datum >: T](x: js.Function1[Datum, Double]): Line[T] = js.native
  def y[Datum >: T](y: js.Function1[Datum, Double]): Line[T] = js.native
  . . .
}

The example

import scala.scalajs.js
import scala.scalajs.js._
import org.scalajs.dom

import org.singlespaced.d3js.Ops._
import org.singlespaced.d3js.d3

object LineGraphExample extends JSApp {

  trait Data {
    var date: Date
    var close: Double
  }

  def main(): Unit = {

    object margin {
      val top = 30
      val right = 20
      val bottom = 30
      val left = 50
    }

    val width = 600 - margin.left - margin.right
    val height = 270 - margin.top - margin.bottom

    val parseDate = d3.time.format("%d-%b-%y").parse(_)

    val x = d3.time.scale().range(Array(0, width))
    val y = d3.scale.linear().range(Array(height, 0))

    val xAxis = d3.svg.axis().scale(x)
      .orient("bottom").ticks(5)
    val yAxis = d3.svg.axis().scale(y)
      .orient("left").ticks(5)

    val valueline = d3.svg.line[Data]() 
      .x { (d: Data) => x(d.date) }
      .y { (d: Data) => y(d.close) }

    val svg = d3.select("body")
      .append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform",
        "translate(" + margin.left + "," + margin.top + ")")

    d3.csv("data.csv", { (error: Any, rawdata: Array[Dictionary[String]]) =>

      val data: Array[Data] = rawdata.map { record =>
        object d extends Data {
          var date = parseDate(record("date"))
          var close = record("close").toDouble
        }
        d
      }

      val Tuple2(minx, maxx) = d3.extent(data.map(_.date))
      x.domain(Array(minx, maxx))

      val maxy = d3.max(data.map(_.close))
      y.domain(Array(0, maxy))

      svg.append("path")
        .attr("class", "line")
        .attr("d", valueline(data))

      svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)

      svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)

      ()
    })
  }
}

timeModule.Scale isn't compatible with behavior.zoom.Scale

In pure JS, I can use

var xScale = d3.time.scale()
    .range([419, 1210])
    .domain([new Date(2015, 10, 1), new Date(2015, 12, 30)]);
var xAxis = d3.svg
    .axis()
    .scale(xScale)
    .orient("bottom");
var zoom = d3.behavior
    .zoom()
    .x(xScale)
    .on("zoom", function() {
        // Redraw the x-axis
        ...
    });

But when moving to Scala with your facade, xScale has type of timeModule.Scale[Double, Double], meanwhile d3.behavior.zoom().x() requires a behavior.zoom.Scale.

Can you help me?

layout.partition

Hi there - thanks for the great job, I enjoyed it a lot already. Any reason why partition got dropped in the moduled rewrite? Which other layout is the best example to mimic so I can add it?

example

I was trying to run an example of it in the workbench-example-app autowire skeleton. I couldn't run it, I got different errors. Would you please add example that runs with the lib?

Support latest version of D3

Currently, I can't use the latest version of D3 (3.5.12 at the moment):

// built.sbt
jsDependencies += "org.webjars" % "d3js" % "3.5.12" / "3.5.12/d3.min.js"

The compilation tells me about the conflict that the current facade is compatible with D3 3.5.6 only.

selection.data key with simple function

To make the API useful

 svg.selectAll[Node](".node").data(force.nodes(), (d: Node, i: Int) => d.id)

should compile, but (d: Node, i: Int) => d.id is not lifted or recognised as a js.thisFunction2

I've read http://stackoverflow.com/questions/27577368/d3-js-key-function-running-twice-on-simple-selector-array-combo. The current definition might be technically spoken correct but of little use if you don't overload it as to accept the above. Instantiating from js.thisFunction2 may be useful to mimic this binding from js in scala. But to pass a closure as argument, it just makes things complex. The point made on stackoverflow is that the passed function should work both on the selected data as well on the new data.
In case of

 svg.selectAll[Node](".node").data[N1,N2](force.nodes(): js.Array[N1] , (d: N2, i: Int) => d.id)

The type relation should be: N2 >: N1 and N2 >: Node
or when N2 == Node then N1 <: Node

as such I would propose both, next to the thisFunction based API if you like

def data[NewDatum <: Datum](data: js.Array[NewDatum], key: js.Function1[Datum, String]): Update[NewDatum] = js.native
def data[NewDatum <: Datum](data: js.Array[NewDatum], key: js.Function2[Datum, Int, String]): Update[NewDatum] = js.native

Empty update selection

First and foremost: Thanks for you library!

When playing around with it, I ran into an issue with the update selection returned by selectAll(..).data(..). Given the following html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>

<!-- Include JavaScript dependencies -->
<script type="text/javascript" src="./target/scala-2.11/scala-js-playground-jsdeps.js"></script>

<!-- Include Scala.js compiled code -->
<script type="text/javascript" src="./target/scala-2.11/scala-js-playground-fastopt.js"></script>

<!-- Run JSApp -->
<script type="text/javascript" src="./target/scala-2.11/scala-js-playground-launcher.js"></script>

<svg>
    <text y="50">Hello</text>
    <text y="100">World</text>
</svg>

</body>
</html>

and the following Scala.js:

import org.singlespaced.d3js.d3
import scala.scalajs.js

object DemoApp extends js.JSApp {

  def main(): Unit = {
    val data = js.Array("0")
    d3.select("body svg").selectAll("text").data(data).style("fill", "orange")
  }

}

I would expect "Hello" to be rendered in orange (the array contains one datum, so there should be one match in the update selection). However, the selection is empty and both text elements appear in black.

The equivalent JS would be:

d3.select("body svg").selectAll("text").data(["0"]).style("fill", "orange")

If I manually enter it in the Chrome Console, everything works as expected.

Key function signature does not seem to match d3 documentation

The BaseSelection#data method's key argument has type js.ThisFunction2[Datum|NewDatum,js.UndefOr[NewDatum], Int, String]

But the 'this' argument of the key function would be a DOM node or an Array according to d3 documentation here:
https://github.com/mbostock/d3/wiki/Selections#data

Also, the documentation does not mention that the 'd' argument could be undefined.

Perhaps a plain js.Function2[Datum, Int, String] would be better here? It would certainly be easier to use. Supplying a function with the current signature is a pain.

Adding area as "d" attribute

I'm trying to implement this: http://bl.ocks.org/mbostock/3883195

    val margin = Margin(top = 20, right = 20, bottom = 30, left = 50)

    val width = 960 - margin.left - margin.right
    val height = 500 - margin.top - margin.bottom

    val parseDate = d3.time.format("%d-%b-%y").parse(_)

    val x = d3.time.scale().range(js.Array(0, width))
    val y = d3.scale.linear().range(js.Array(height, 0))

    val xAxis = d3.svg.axis().scale(x).orient("bottom")
    val yAxis = d3.svg.axis().scale(y).orient("left")

    val xf: js.Function2[DataArray, Int, Double] = (d: DataArray, i: Int) => x(d(i).date)
    val yf: js.Function2[DataArray, Int, Double] = (d: DataArray, i: Int) => x(d(i).close)

    val area = d3.svg.area()
      .x(xf)
      .y0(height)
      .y1(yf)


    val svg: Selection[EventTarget] = d3.select("body")
      .append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    d3.tsv("apple.tsv", (error: Any, rawdata: Array[Dictionary[String]]) => {

      val data: Array[Data] = rawdata.map { line =>
        object d extends Data {
          var date = parseDate(line("date"))
          var close = line("close").toDouble
        }
        d
      }

      val Tuple2(minX, maxX) = d3.extent(data.map(_.date))
      x.domain(Array(minX, maxX))

      val maxY = d3.max(data.map(_.close))
      y.domain(Array(0, maxY))

      svg.append("path")
        .datum(data)
        .attr("class", "area")
        .attr("d", area)

but last line does not compile since

overloaded method value attr with alternatives:
[error]   (name: String,value: scala.scalajs.js.Function3[scala.scalajs.js.Array[Data],Int,scala.scalajs.js.UndefOr[Int],scala.scalajs.js.|[scala.scalajs.js.|[Double,String],Boolean]])org.singlespaced.d3js.selection.Update[scala.scalajs.js.Array[Data]] <and>
[error]   (name: String,value: org.singlespaced.d3js.d3.Primitive)org.singlespaced.d3js.selection.Update[scala.scalajs.js.Array[Data]]
[error]  cannot be applied to (String, org.singlespaced.d3js.svg.Area[DataArray])
[error]         .attr("d", area)
[error]          ^

As error said, there's no signature that allows to pass an Area instance.

By the way, I'll do a pull request to put this into examples.

Cannot use call

I followed the simple code taken from AxisTest.scala

val x = d3.time.scale().range(js.Array(0,  1000))
val xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(5)
d3.select("p").append("svg").call(xAxis)

but the compiler/IDE reports that call expects a js.Function, not Axis.

.each and d3.select(this)

In the .each function of d3, often code is executed as d3.select(this). However as far as my knowledge goes, in scala.js d3 it is not possible to currently perform this action.

One possibility would be using the ThisFunction from scala.js, this would allow the usage of this as an parameter.

Support scala-js 1.X

Currently the library only supports scala-js 0.6 which is already in EOL. Would it be possible to upgrade to scala-js 1.7.1 (the latest).

Ideally with support for Scala 3.x.

I can help if necessary.

Ambiguous reference to a JS library: 3.5.17/d3.min.js

Hello!
I am trying to use the scala JS D3 façade within a project, and i am facing an issue, apparently coming from the scala-js-d3:compile build phase :

Ambiguous reference to a JS library: 3.5.17/d3.min.js
[error]   Possible paths found on the classpath:
[error]   - META-INF/resources/webjars/d3/3.5.17/d3.min.js
[error]   - META-INF/resources/webjars/d3js/3.5.17/d3.min.js
[error]   originating from: scala-js-d3:compile

My build.sbt part associated with scala js dependencies is given in the following :

enablePlugins(ScalaJSPlugin)
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "0.9.6"
scalaJSUseMainModuleInitializer := true
libraryDependencies += "org.singlespaced" %%% "scalajs-d3" % "0.3.4"

Should the façade build.sbt file contains the following way to load d3js, to avoid ambiguity ?

jsDependencies += "org.webjars" % "d3js" % "3.5.17" / "d3js/3.5.17/d3.min.js"

instead of

jsDependencies += "org.webjars" % "d3js" % "3.5.17" / "3.5.17/d3.min.js"

Thanks in advance!

Adding text to the Bar charts example

I would like to add text values in the barchart similar to the following two examples:
https://alignedleft.com/tutorials/d3/making-a-bar-chart
https://stackoverflow.com/questions/18057917/adding-label-on-a-d3-bar-chart

here is my example source code:

val graphHeight = 450

      //The width of each bar.
      val barWidth = 80

      //The distance between each bar.
      val barSeparation = 10

      //The maximum value of the data.
      val maxData = 50

      //The actual horizontal distance from drawing one bar rectangle to drawing the next.
      val horizontalBarDistance = barWidth + barSeparation

      //The value to multiply each bar's value by to get its height.
      val barHeightMultiplier = graphHeight / maxData;

      //Color for start
      val color = d3.rgb("DarkSlateBlue")

      val my_data = js.Array(8, 22, 31, 36, 48, 17, 25)

      val rectXFun = (d: Int, i: Int) => i * horizontalBarDistance
      val rectYFun = (d: Int) => graphHeight - d * barHeightMultiplier

      val rectXFun2 = (d: Int, i: Int) => i * horizontalBarDistance +5
      val rectYFun2 = (d: Int) => graphHeight - d * barHeightMultiplier +15
      val rectHeightFun = (d: Int) => d * barHeightMultiplier
      val rectColorFun = (d: Int, i: Int) => color.brighter(i * 0.5).toString

      val svg = d3.select("#d3Container2").append("svg").attr("width", "100%").attr("height", "450px")
      val sel = svg.selectAll("rect").data(my_data)
      val sel2 = sel.enter()
        .append("rect")
        .attr("x", rectXFun)
        .attr("y", rectYFun)
        .attr("width", barWidth)
        .attr("height", rectHeightFun)
        .style("fill", rectColorFun)

        sel2.append("text").
        text((d: Int,i: Int) => d.toString)
        .attr("x", rectXFun2)
        .attr("y", rectYFun2)
        .style("fill","black")
        .style("text-anchor", "middle")

        val svg_text =svg.selectAll("text")
        .data(my_data)
        .enter()
        .append("text")
        .text((d: Int,i: Int) => d.toString)
        .attr("x", rectXFun2)
        .attr("y", rectYFun2)
        .style("fill","black")
        .style("text-anchor", "middle")

Both adding text to the rectangle and adding text to the svg seem to fail.

Thanks in advance

selection.data

The current implementation requires a Function3 as key function.

def data[NewDatum](data: js.Array[NewDatum], key:js.Function3[NewDatum, Int, Int, String]): Update[NewDatum] = js.native

This implementation gives execution errors when running with d3.js (master 20 May 2015 > tag 3.5.9)
complaining that the 3 argument is undefined iso Int.

The d3.js documentation only describes a function with one or two arguments: datum and index.

This can be corrected :

def data[NewDatum](data: js.Array[NewDatum], key: js.Function2[NewDatum, Int, String]): Update[NewDatum] = js.native

Testing with uTest

Thanks for the fine work. I'm curious as to what are the best examples for, or bases for, writing tests for the use of this facade with uTest. I see some tests in src/test. But I don't see anything other than a skeleton for the example.

Thanks so much.

Question on radial

Hi,

I'm trying to make this code work but it does not compile

val line = d3.svg.line.radial().interpolate("basis").tension(0).radius(100)

Is something wrong in what I wrote or simply this function is not supported yet? I saw the a radial trait is present in code but it does not seem connected to the rest of the code.

Possible issue to selection.data

Hello,

I'm trying to adapt an example to render a simple HTML-table from here.

Here is my code.

Code compiled successful, but when page is loading, I have the error:

Uncaught scala.scalajs.runtime.UndefinedBehaviorError: An undefined behavior was detected: undefined is not an instance of java.lang.Integer scalajsenv.js:192

May be I do something wrong. For example, I cannot implement a text() method. Take a look, please.

Thanks

Usage of DatumFunction

Hello,

I am trying to "port" this Scatterplot example (http://bl.ocks.org/weiglemc/6185069) to scala-js-d3

Unfortunately, I am having some trouble understanding the proper use of DatumFunction. Please see my code, which I just added to your example project:

https://gist.github.com/littler00t/943b1cd79c7922229dff

See lines 121ff : I understand the return type of DatumFunction should be String and the "Datum" type is also String.

Nevertheless, I get compilation error:

[error] ... scala-js-d3-example-app/src/main/scala/example/ScalaJSExample.scala:121: type mismatch;
[error]  found   : (String, Int, Int) => String
[error]  required: legend.DatumFunction[org.singlespaced.d3js.d3.Primitive]
[error]     (which expands to)  scala.scalajs.js.Function3[String,Int,Int,scala.scalajs.js.|[scala.scalajs.js.|[Double,String],Boolean]]
[error]     val transformLegend: legend.DatumFunction[d3.Primitive] = { (d: String, x: Int, y: Int) => "translate(0," + x * 20 + ")" }
[error]                                                                                             ^
[error] ... scala-js-d3-example-app/src/main/scala/example/ScalaJSExample.scala:124: type mismatch;
[error]  found   : (String, Int, Int) => String
[error]  required: scala.scalajs.js.Function3[String,Int,Int,org.singlespaced.d3js.d3.Primitive]
[error]     (which expands to)  scala.scalajs.js.Function3[String,Int,Int,scala.scalajs.js.|[scala.scalajs.js.|[Double,String],Boolean]]
[error]     val transformLegend2: scala.scalajs.js.Function3[String, Int, Int, d3.Primitive] = { (d: String, x: Int, y: Int) => "translate(0," + x * 20 + ")" }
[error]                                                                                                                      ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed

Would be great if you could help. It's probably just a minor issue coming from my lack of understanding so any help is greatly appreciated :-) If I finish the scatterplot, maybe it can serve as an example on how to handle this kind of stuff.

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.