What is the equivalent for new after require in ScalaJS? - scala.js

I see here
javascript:
var D3Funnel = require('d3-funnel');
var chart = new D3Funnel('#funnel');
I managed to get the first line working in ScalaJS by using:
ScalaJS:
val Funnel = js.Dynamic.global.require("d3-funnel")
but what should be the equivalent to the second line var chart = new D3Funnel('#funnel'); in ScalaJS?

It is currently a bit ugly. To create an instance of a dynamic class, you have to use js.Dynamic.newInstance:
import scala.scalajs.js
val chart = js.Dynamic.newInstance(Funnel)("#funnel")
From there, I recommend casting chart to a statically-defined API:
#js.native
trait Funnel extends js.Object {
def someMethodOfFunnel(): Unit = js.native
}
val chart = js.Dynamic.newInstance(Funnel)("#funnel").asInstanceOf[Funnel]
chart.someMethodOfFunnel() // statically typed

Related

Setting parameters in scala classes

I am trying to get familiar with classes in Scala(spark) and I wrote a simple wrapper class over XGBoostClassifier to experiment with. Once that wrapper class was ready, I tried setting some parameters but I am getting errors and can't find much help online
This is the class I am using
class trialXGBClassifier{
var xgb_cls_object: XGBoostClassifier = _
}
I also wrote a small utility function to convert JSON to a Map (string, string)
def jsonToMap(jsonString: String): Map[String, String] = {
val jsonMap = JSON.parseFull(jsonString).get.asInstanceOf[Map[String, String]]
return jsonMap
}
And this is the code that's giving me the error
var params = """{"numRound": "10"}"""
var trial_xgb = new trialXGBClassifier
trial_xgb.xgb_cls_object.setSeed(jsonToMap(params)("numRound").toLong)
This is the error message I get
java.lang.NullPointerException
... 61 elided
I tried doing the following using the actual ml.dmlc class and it works
var xgb_orig = new XGBoostClassifier
xgb_orig.setSeed(jsonToMap(params)("numRound").toLong)
xgb_orig.getSeed #10
Whats the reason behind this error and how do I fix this?
In Scala, people try to use val instead of var in all places where such usage possible. Also, they try to use case class or sealed trait instead of just class.
So, there's a very nice way to avoid such kind of issues using case class:
case class TrialXGBClassifier(xgb_cls_object: XGBoostClassifier)
And then the best option to use your wrapper only when you have something to wrap:
val xgb_orig = new XGBoostClassifier
xgb_orig.setSeed(jsonToMap(params)("numRound").toLong)
val v = TrialXGBClassifier(xgb_orig)
And you even can omit xgb_orig declaration:
val v = TrialXGBClassifier(new XGBoostClassifier)
v.xgb_cls_object.setSeed(jsonToMap(params)("numRound").toLong)

how to use showdown.js in scalajs?

I want use showdown.js library on my scalajs project.
How could I use scalajs to replace javascript code:
var converter = new showdown.Converter(),
text = '#hello, markdown!',
html = converter.makeHtml(text);
I have find a dependencies with jsDependencies += "org.webjars.bower" % "github-com-showdownjs-showdown" % "1.4.3" / "1.4.3/showdown.js" commonJSName "Showdown", but its not enough. Should I write a js.native binding to the library refer in scala.js document?
A example is welcome! Thanks
You should indeed write an #js.native binding for the library, unless you find a published library that does it for you.
For the small example that you show, the binding would look like this:
#js.native
#JSGlobal("showdown.Converter")
class Converter extends js.Object {
def makeHtml(text: String): String = js.native
}
which then allows you to write
val converter = new Converter()
val text = "#hello, markdown!"
val html = converter.makeHtml(text)

How to attach a HashMap to a Configuration object in Flink?

I want to share a HashMap across every node in Flink and allow the nodes to update that HashMap. I have this code so far:
object ParallelStreams {
val env = StreamExecutionEnvironment.getExecutionEnvironment
//Is there a way to attach a HashMap to this config variable?
val config = new Configuration()
config.setClass("HashMap", Class[CustomGlobal])
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
class CustomGlobal extends ExecutionConfig.GlobalJobParameters {
override def toMap: util.Map[String, String] = {
new HashMap[String, String]()
}
}
class MyCoMap extends RichCoMapFunction[String, String, String] {
var users: HashMap[String, String] = null
//How do I get access the HashMap I attach to the global config here?
override def open(parameters: Configuration): Unit = {
super.open(parameters)
val globalParams = getRuntimeContext.getExecutionConfig.getGlobalJobParameters
val globalConf = globalParams[Configuration]
val hashMap = globalConf.getClass
}
//Other functions to override here
}
}
I was wondering if you can attach a custom object to the config variable created here val config = new Configuration()? (Please see comments in the code above).
I noticed you can only attach primitive values. I created a custom class that extends ExecutionConfig.GlobalJobParameters and attached that class by doing config.setClass("HashMap", Class[CustomGlobal]) but I am not sure if that is how you are supposed to do it?
The common way to distribute parameters to operators is to have them as regular member variables in the function class. The function object that is created and assigned during plan construction is serialized and shipped to all workers. So you don't have to pass parameters via a configuration.
This would look as follows
class MyMapper(map: HashMap) extends MapFunction[String, String] {
// class definition
}
val inStream: DataStream[String] = ???
val myHashMap: HashMap = ???
val myMapper: MyMapper = new MyMapper(myHashMap)
val mappedStream: DataStream[String] = inStream.map(myMapper)
The myMapper object is serialized (using Java serialization) and shipped for execution. So the type of map must implement the Java Serializable interface.
EDIT: I missed the part that you want the map to be updatable from all parallel tasks. That is not possible with Flink. You would have to either fully replicate the map and all updated (by broadcasting) or use an external system (key-value store) for that.

JavaScript object as function parameter

I'm writting a function transpiled with Scala.js that should accept any random JavaScript object.
Ex:
// This has been transpiled using Scala.js
var my_service = new com.myself.Service();
// This is plain JavaScript
var result1 = service({ hello: "yolo" });
var result2 = service({ whatever: "ok", really: { yes: "right", no: "don't" } });
However, I can't find the input type that matches it.
What would be the Scala-function signature to get such a thing?
Could it be used then as a "Scala/JS case class" easily?
Note (if it helps giving a direction for the answers): these objects have, in the real life, an expected schema but it cannot be created as JS object generated from Scala.js since it comes from another consumed service.
Since the objects have an expected schema, its probably easiest to define a facade type:
#js.native
trait Args extends js.Object {
val hello: js.UndefOr[String]
val whatever: js.UndefOr[String]
val really: js.UndefOr[ReallyArgs]
}
#js.native
trait Really extends js.Object {
val yes: String
val no: String
}
def myMethod(args: Args): Unit = {
println(args.hello)
println(args.really.map(_.yes))
}

Dynamic calls to JavaScript in Scala.js

I am wondering how to do dynamic operations in Scala.js. For example, looking at the jQuery example in the tutorial, my understanding is you define the following in scala:
object TutorialApp extends JSApp {
def appendPar(msg: String) = {
jQuery("body").append("<p>" + msg + "</p>")
}
def main(): Unit = {
appendPar("Hello World")
}
}
This is all stuff that is generated statically at compile time. But I didn't see any way I could set the message parameter dynamically (eg read it from a DB).
I don't know about reading it from the DB. That is beyond the scope of this question (or you need to rephrase the question). Maybe an AJAX call or something?
But to read it from, for example, an <input> tag, you'd do something like that:
def main(): Unit = {
val msg = jQuery("#myinput").value()
appendPar(msg)
}
(Although in this case it probably doesn't make any sense in a main method, but that's not the point.)
I mean, msg is just a val (so like a var in JS but immutable). You can fetch it from any dynamic source of information as you like.
Edit:
If you want to access some data generated dynamically by the server when rendering the page, you can do so like this:
First, have your server generate the data as a global var in a <script> tag in the generated HTML. Something like:
<script type="text/javascript">
var mydata = {
msg: "Some text generated dynamically by the server"
}
</script>
Make sure to emit this script tag before the call to the main() function of Scala.js!
Then, from Scala.js, you can access these data with the js.Dynamic interface:
import scala.scalajs.js
val mydata = js.Dynamic.global.mydata
val msg = mydata.msg.asInstanceOf[String]
If your data have always a relatively static structure, it may be useful to declare yourself a facade type for them:
#JSName("mydata")
object MyData extends js.Object {
val msg: String = ???
}
Then you can access it without resorting to the Dynamic API:
val msg = MyData.msg
Adding to (and attempting to generalize) sjrd's answer: To call a javaScriptMethod on an object of a JavaScriptType you first write a type facade for it:
import scala.scalajs.js
import scala.scalajs.js.annotation.JSName
#js.native
#JSName("JavaScriptType")
class MyType() extends js.Object {
def javaScriptMethod(someParam: String) = js.native
}
After that, it's a piece of cake to use the JavaScript code using Scala on the client side:
val myObject = new MyType()
myObject.javaScriptMethod("Yippie")
As a concrete example, to use Stack Overflow's Markdown converter Pagedown in your Scala.js application you'd first create the type facade for it:
#js.native
#JSName("Markdown.Converter")
class MarkdownConverter() extends js.Object {
def makeHtml(txtUsingMarkdown: String): String = js.native
}
If you are learning Scala.js using this great tutorial project, you can declare the dependency on Pagedown in Settings.scala like this:
val jsDependencies = Def.setting(Seq(
"org.webjars.bower" % "pagedown" % "1.1.0" / "Markdown.Converter.js",
//...
Then you can simply do
val html = new MarkdownConverter().makeHtml("this is *nice*")
Here's another example where we call a static method of SparkMD5.
We define an object as opposed to the class of the previous example. Also, we can omit the #JSName annotation since our Scala type is eponymous with the JavaScript type:
#js.native
object SparkMD5 extends js.Object {
def hash(str: String, raw: Boolean = false): String = js.native
}