我需要從給定的資料中以編程方式實體化幾個文本元素。這些文本元素應該被一個矩形包圍,該矩形具有最大寬度的文本元素的寬度。像這樣:

目前,我正在使用一種方法來創建文本節點,如下所示:
let textnodes = data.map(d => {
let svgText = document.createElementNS(d3.namespaces['svg'],'text')
let textNode = document.createTextNode(d.text)
svgText.appendChild(textNode)
return svgText
})
之后,我計算了寬度,最后應用了一個最大值函式,這里getTextWidth是一個自制的方法:
Math.max(...textnodes.map(t=> {
return t.firstChild ? this.getTextWidth(
t.firstChild.nodeValue,
this.config.attributesFontSize "px " this.config.attributesFont ) : 0
}))
我的問題是:有沒有辦法SVGTextElement從 D3 創建提供的型別而不是使用document.createElementNS(...)?我問的原因是,這SVGTextElement使我有可能使用免費getBBox()為我提供width財產的方法。理想情況下,我想像這樣實體化我的文本節點:
data.map({ d =>
let text = new SVGTextElement()
text.setAttribute(...)
...
})
但是,不允許使用這樣的建構式。
uj5u.com熱心網友回復:
該問題有多種解決方案:
第一個可能的解決方案是將結果(就稱為型別斷言的TypeScript而言)強制轉換為,
SVGTextElement因為您知道您的呼叫document.createElementNS()保證會產生該型別:const svgText = document.createElementNS(d3.namespaces['svg'], "text") as SVGTextElement;但是,通過讓編譯器為您完成作業,有一個更優雅的解決方案。在該方法的DOM 型別定義中,
.createElementNS有一個多載,尤其是在 SVG 命名空間中創建元素時:createElementNS<K extends keyof SVGElementTagNameMap>(namespaceURI: "http://www.w3.org/2000/svg", qualifiedName: K): SVGElementTagNameMap[K];在這個定義中,這
SVGElementTagNameMap是一個將 SVG 命名空間的所有元素名稱映射到相應型別的介面。因此,上面的型別定義可以理解為:如果namespaceURI是"http://www.w3.org/2000/svg"并且qualifiedName是介面中包含的鍵,SVGElementTagNameMap則編譯器推斷回傳型別是該介面中參考的元素型別qualifiedName。const svgText = document.createElementNS("http://www.w3.org/2000/svg", "text");對于上面的行,
element將是SVGTextElement您需要的型別。旁注:由于某些我無法理解的原因,您必須將命名空間指定為字串,您不能通過
d3.namespaces.svg或任何其他參考來參考該字串。也許有人可以填寫缺失的資訊以進一步改進這個答案。如果您想要一個 D3-ish 解決方案,您可以使用
d3.create()它將創建一個分離的元素并回傳一個包含該單個元素的新選擇。但是,編譯器將無法自動推斷型別,因為您需要指定svg:SVG 命名空間的前綴。但是,您可以使用泛型來指定型別,這可以從方法的型別定義中看出:export function create<NewGElement extends Element>(name: string): Selection<NewGElement, undefined, null, undefined>;您的代碼可能如下所示:
const svgTextSel = create<SVGTextElement>("svg:text");
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/427028.html
標籤:javascript 打字稿 dom d3.js
上一篇:值未在瀏覽器中列印
