输入fa和xE7;Scala.JS中JS库的ade

输入fa和xE7;Scala.JS中JS库的ade,scala,scala.js,Scala,Scala.js,我正试图为我的图书馆写一个打印的外观,如下所示 我希望能够翻译的是如下所示的呼叫: var Polygon = require('paths-js/Polygon'); var polygon = Polygon({ points: [[1, 3], [2, 5], [3, 4], [2, 0]], closed: true }); 进入 但我不确定我需要做什么才能达到这一点 我所做的事情如下 type Point = (Number, Number) trait PolygonOpt

我正试图为我的图书馆写一个打印的外观,如下所示

我希望能够翻译的是如下所示的呼叫:

var Polygon = require('paths-js/Polygon');
var polygon = Polygon({
  points: [[1, 3], [2, 5], [3, 4], [2, 0]],
  closed: true
});
进入

但我不确定我需要做什么才能达到这一点

我所做的事情如下

type Point = (Number, Number)
trait PolygonOpt {
  val points: Array[Point]
  val closed: Boolean
}
@JSName("paths.Polygon")
object Polygon extends js.Object {
  def apply(options: PolygonOpt): Shape = js.native
}
然后,我可以像这样调用它

class Opt extends PolygonOpt {
  val points: Array[Point] = Array((1, 2), (3, 4), (5, 6))
  val closed = true
}
val opts = new Opt
val poly = Polygon(opts) 
我对此有一些疑问:

  • 我正处在一个所有东西都可以编译的时刻,但最终的javascript在调用时失败。我认为这是因为我正在传递一个
    PolygonOpt
    的实例,而运行时需要一个javascript对象文本
  • 点的定义是否转换为包含两个组件的js数组
  • 我希望能够重载
    Polygon.apply
    def apply(points:Seq[Point],closed:Boolean):Shape
    ,但是scala.js不允许我在
    Polygon
    内部编写方法实现,因为它扩展了
    js.Object
此外,我有一个使用common.js的库版本(它分为几个文件,每个组件一个),还有一个可以用作单个
标记,将所有内容放在名称空间
路径下(这就是我现在使用的)


哪一个更适合Scala.js包装器?

首先,请确保阅读,包括。我想你已经这么做了,因为你已经有了一些合理的东西。但是,您应该特别注意那些表示Scala类型和JavaScript类型完全不相关的部分,除非明确提到

因此,
Int
是一个合适的JS
数字(在Int的范围内)。但是
数组[点]
与JavaScript数组无关。一个
元组2
(例如
(1,3)
)甚至更不如此。因此:

点的定义是否转换为包含两个组件的js数组

不,不是。因此,JavaScript完全无法理解它。是的

更糟糕的是,
PolygonOpt
,因为它不扩展
js.Object
,在JavaScript中也是完全不透明的,这就解释了为什么不能看到
点和
关闭的
字段

首先要做的是使用JavaScript可理解的类型(扩展
js.Object
)准确地键入JSAPI。在这种情况下,它将如下所示:

type JSPoint = js.Array[Int] // or Double

trait PolygonOpts extends js.Object {
  val points: js.Array[JSPoint] = js.native
  val closed: Boolean = js.native
}

@JSName("paths.Polygon")
object Polygon extends js.Object {
  def apply(options: PolygonOpt): Shape = js.native
}
现在,问题是创建
PolygonOpts
的实例并不容易。有关此信息,请参阅:

最后,您可以通过隐式扩展公开您首先想要的Scala-esque API:

import js.JSConverters._

object PolygonImplicits {
  implicit class PolygonObjOps(val self: Polygon.type) extends AnyVal {
    def apply(points: List[(Int, Int)], closed: Boolean): Shape = {
      val jsPoints =
        for ((x, y) <- points.toJSArray)
          yield js.Array(x, y)
      Polygon(PolygonOpts(jsPoints, closed))
    }
  }
}
导入js.jsconverter_
对象多克隆implicits{
隐式类PolygonObjOps(val self:Polygon.type)扩展了AnyVal{
定义应用(点:列表[(Int,Int)],闭合:布尔):形状={
瓦尔jsPoints=

对于((x,y)非常感谢!这看起来像是一种非常常见的情况(将接受对象文字的函数转换为接受命名参数的函数)需要大量的样板文件…我想知道是否值得为此编写一个宏。不幸的是,我不能在名为apply的隐式扩展中有一个方法,因为它已经存在于原始对象上,并且编译器不寻找隐式转换。我可能会放弃使用
PolygonOpts并公开更具scalasque的接口。不过,这有点不幸,因为从javascript端传递
PolygonOpts
的实例会比较困难,但这种情况不应该经常发生
object PolygonOpts {
  def apply(points: js.Array[JSPoint], closed: Boolean): PolygonOpts = {
    js.Dynamic.literal(
        points = points,
        closed = closed
    ).asInstanceOf[PolygonOpts]
  }
}
import js.JSConverters._

object PolygonImplicits {
  implicit class PolygonObjOps(val self: Polygon.type) extends AnyVal {
    def apply(points: List[(Int, Int)], closed: Boolean): Shape = {
      val jsPoints =
        for ((x, y) <- points.toJSArray)
          yield js.Array(x, y)
      Polygon(PolygonOpts(jsPoints, closed))
    }
  }
}