在D3.js Scala.js绑定中如何实例化scala.scalajs.js.ThisFunction3
解决Scala.js中d3
data()方法的ThisFunction类型不匹配问题 这个类型不匹配的核心原因是你对d3 data()方法的key函数签名理解有误,加上Scala.js的ThisFunction类型需要严格对应函数的上下文和参数列表。让我一步步帮你理清:
先明确d3 key函数的实际签名
在d3中,selection.data()的key函数只接受两个显式参数:
- 当前绑定的数据项(如果是enter阶段的元素,会是
undefined) - 元素的索引
而函数的this上下文会指向对应的DOM节点(也就是你代码里的Node)。
在Scala.js的d3类型定义中,这个函数对应的类型是ThisFunction2[Node, js.UndefOr[Resource], Int, String],拆解一下:
Node:函数this上下文的类型js.UndefOr[Resource]:第一个显式参数(数据项,用UndefOr对应d3的undefined)Int:第二个显式参数(索引)String:返回的key值类型
你之前的写法把Node当成了第一个显式参数,导致写了三个参数,自然和期望的ThisFunction2(两个显式参数)不匹配。
正确的实例化方式
这里提供两种可靠的写法:
方式1:显式使用js.ThisFunction2(推荐,类型更清晰)
val selection = myG.selectAll(".res") .data[Resource]( // 数据生成函数 (container: Container, _: Int) => container.resources.toJSArray, // 正确的key函数 js.ThisFunction2((domNode: Node, dataItem: js.UndefOr[Resource], index: Int) => { // 把js.UndefOr转换成Scala的Option处理 val resourceOpt = dataItem.toOption // 这里替换成你实际需要的key生成逻辑,比如取resource的id resourceOpt.map(_.id).getOrElse("") }) )
方式2:利用Scala.js隐式转换,通过js.Dynamic获取this
如果你觉得显式写ThisFunction2有点繁琐,也可以用普通匿名函数,再动态获取this上下文:
val selection = myG.selectAll(".res") .data[Resource]( (container: Container, _: Int) => container.resources.toJSArray, (dataItem: js.UndefOr[Resource], index: Int) => { // 动态获取当前的DOM节点(this上下文) val domNode = js.Dynamic.global.this.asInstanceOf[Node] // 同样处理数据项并生成key dataItem.toOption.map(_.id).getOrElse("") } )
关键注意点
- 不要把
this上下文的DOM节点当成显式参数传入,d3会把它绑定到函数的this上,Scala.js用ThisFunctionN系列类型来处理这种带上下文的函数。 - 数据项的类型是
js.UndefOr[Resource]而不是Option[Resource],这是Scala.js对应JS中undefined的类型,用.toOption可以轻松转换成Scala熟悉的Option来处理空值。
内容的提问来源于stack exchange,提问作者Florian Baierl
相关产品推荐
相关产品推荐

