我有以下代码,我尝试强类型,以便更容易维护。
但是对于菜单变量,我收到以下错误:
[ts]
Type '(x: number, y: number) => void' is not assignable to type 'ContextMenu'.
Property 'items' is missing in type '(x: number, y: number) => void'.
import * as d3 from "d3";
import "d3-selection-multi";
interface ContextMenu {
(x: number, y: number) : void;
items(items?: string[]): string[] | this;
remove(): void;
}
export function contextMenu(): ContextMenu {
var height,
width,
margin = 0.1, // fraction of width
items = [],
rescale: boolean = false,
style = {
'rect': {
'mouseout': {
"fill": 'rgb(244,244,244)',
"stroke": 'white',
"strokeWidth": '1px'
},
'mouseover': {
"fill": 'rgb(200,200,200)'
}
},
'text': {
'fill': 'steelblue',
'font-size': '13'
}
};
var menu: ContextMenu = function (x:number, y:number) {
menu.remove();
scaleItems();
// Draw the menu
d3.selectAll('svg.chart')
.append('g').attr('class', 'context-menu')
.selectAll('tmp')
.data(items).enter()
.append('g').attr('class', 'menu-entry')
.style('cursor', 'pointer')
.on('mouseover', function() {
d3.select(this).select('rect').styles((<any>style).rect.mouseover) })
.on('mouseout', function() {
d3.select(this).select('rect').styles((<any>style).rect.mouseout) });
d3.selectAll('.menu-entry')
.append('rect')
.attr('x', x)
.attr('y', (d, i) => y + (i * height))
.attr('width', width)
.attr('height', height)
.styles((<any>style).rect.mouseout);
d3.selectAll('.menu-entry')
.append('text')
.text((d: string) => d)
.attr('x', x)
.attr('y', (d, i) => y + (i * height))
.attr('dy', height - margin / 2)
.attr('dx', margin)
.styles((<any>style).text);
// Other interactions
d3.select('body')
.on('click', function() {
d3.select('.context-menu').remove();
});
}
menu.remove = function() {
d3.selectAll(".context-menu").remove();
};
menu.items = function(_?) {
return (!arguments.length)
? items
:(items = _, rescale = true, menu);
}
// Automatically set width, height, and margin;
function scaleItems() {
if (!rescale) {
return;
}
d3.selectAll('svg').selectAll('tmp')
.data(items).enter()
.append('text')
.text(d => d)
.styles(<any>style.text)
.attr('x', -1000)
.attr('y', -1000)
.attr('class', 'tmp');
var z = d3.selectAll('.tmp')
.nodes()
.map((x:any) => x.getBBox());
width = d3.max(z.map(x => x.width));
margin = margin * width;
width = width + 2 * margin;
height = d3.max(z.map(x => x.height + margin / 2 ));
// cleanup
d3.selectAll('.tmp').remove();
rescale = false;
}
return menu;
}
如何编译代码但保持相同代码风格的惯用D3?
答案 0 :(得分:1)
可悲的是,在您的情况下,没有惯用的扩展功能的方法。唯一的后备是将菜单功能转换为val myValue = f()
val myList: List<Any>
if (myValue != null) {
myList = listOf(myValue)
} else {
myList = emptyList()
}
。
any
TypeScript有另一个功能调用“名称空间合并”以适应扩展函数文字。
var menu: ContextMenu = function (x:number, y:number) {
// ....
} as any
但是,function menu () {}
namespace menu {
export function remove() {}
}
menu.remove() // compiles
只能出现在模块的顶层或嵌套在另一个命名空间中。你不能在函数闭包中声明它。因此,在这种情况下,您必须以任何方式回退到namespace
。