我遇到一个错误,即使元素是画布,也无法调用getContext。
var canvas = document.getElementById(id);
console.log(canvas, canvas.nodeName);
var ctx = canvas.getContext('2d');
谢谢!
它的片段独立工作,但不在脚本
中
var canvas = document.getElementById( '0_0' );
document.write(canvas.getContext('2d'));

<g class="node" transform="translate(210,330)">
<canvas x="-8" y="-8" id="0_0"></canvas>
</g>
&#13;
<canvas x="-8" y="-8" id="0_0"> "canvas"
Uncaught TypeError: canvas.getContext is not a function
at Array.populateNodes (script.js:95)
at Array.Co.call (d3.v3.min.js:3)
at gen_graph (script.js:63)
at Object.success (main.js:16)
at i (jquery.min.js:2)
at Object.fireWith [as resolveWith] (jquery.min.js:2)
at A (jquery.min.js:4)
at XMLHttpRequest.<anonymous> (jquery.min.js:4)
js,使用d3:
道歉我的JS可能有多糟糕,我很陌生
答案 0 :(得分:4)
我认为“canvas”元素被d3视为SVG的未知“画布”元素。所以“canvas”元素没有映射到HTMLCanvasElement而是映射到文档的domtree中的SVGUnknownElement,因此SVGUnknownElement的getContext是未定义的。
要解决这个问题,你应该用foreignObject elemente包装“canvas”元素,并将xhtml命名空间添加到“canvas”元素。
我不擅长d3,请尝试使用d3构建此结构。
<g class="node" transform="translate(210,330)">
<foreignObject x="-8" y="-8">
<canvas id="0_0" xmlns="http://www.w3.org/1999/xhtml"></canvas>
</foreignObject>
</g>
或者使用image元素而不是“canvas”元素来放置由(html)canvas元素创建的图像。
SVG结构
<g class="node" transform="translate(210,330)">
<image x="-8" y="-8" id="0_0"/>
</g>
Javascript代码
//create canvas element.
//var canvas = document.getElementById(nodes[i].__data__.name);
var canvas = document.createElement("canvas");
//console.log(canvas, canvas.nodeName);
var ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
var idata = ctx.createImageData(width, height);
idata.data.set(buffer);
ctx.putImageData(idata, 0, 0);
//set image created by canvas to image element.
var image = document.getElementById(nodes[i].__data__.name);
image.width.baseVal.value = width;
image.height.baseVal.value = height;
image.href.baseVal = canvas.toDataURL();
答案 1 :(得分:0)
我实际上使用d3 v5可以正常工作。我正在打字稿中进行此操作,因此进行了一些估算。
一个问题是,如果仅按常规d3方式附加元素(selection.append()),则会得到更通用类型的选择。您不能仅通过投射来解决此问题。您要做的就是使用document.createElement()在DOM中创建它,然后调用appendChild()放置它。当您这样做时,您将得到一个类型为HTMLCanvasElement的画布。
我没有意识到的一个技巧是,您必须同时在foreignObject和canvas中指定尺寸,否则它将被裁剪。
我在有棱角的土地上,所以看起来像这样
import * as d3 from 'd3';
...
private svg: d3.Selection<Element, any, any, any>
private canvasNode: HTMLCanvasElement
constructor(private root: ElementRef) {}
let foreigner = this.svg.append("foreignObject")
foreigner.attr("width", "800")
foreigner.attr("height", "600")
let canvas = document.createElement("canvas")
canvas.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
canvas.textContent = 'Drawing canvas is not supported'
this.canvasNode = foreigner.node().appendChild(canvas)
this.canvasNode.setAttribute("width", "800")
this.canvasNode.setAttribute("height", "600")
我的组件实现了AfterViewInit,因此我可以延迟实际绘制(尽管您不必这样做):
ngAfterViewInit(): void {
let ctx: CanvasRenderingContext2D = this.canvasNode.getContext('2d')
this.draw(ctx)
}
最后,您可以借鉴一些东西:
draw(ctx: CanvasRenderingContext2D): void {
ctx.save()
ctx.strokeStyle = "#FF0000"
ctx.fillStyle = "#00FFFF"
ctx.moveTo(0,0)
ctx.lineTo(2000, 1000);
ctx.stroke();
ctx.restore()
console.log("drawn")
}
我一直在使用angular和d3(在打字稿中)。有时候正确设置所有类型并不容易,但是值得付出努力。
希望这对某人有帮助。
答案 2 :(得分:0)
使用D3.js,至关重要的是使用.create('xhtml:canvas')
或.append('xhtml:canvas')
在适当的命名空间中创建canvas元素。 xmlns
属性很不错,但是大多数现代HTML5浏览器都会忽略它。
这是完整的D3.js示例:
const svg = d3.select('body').append('svg')
.style('width', '100%')
.style('height', '100%');
const group = svg.append('g')
.attr('class', 'node')
.attr('transform', 'translate(10,10)');
const foreignObject = group.append('foreignObject')
.attr('width', 100)
.attr('height', 100);
const canvas = foreignObject.append('xhtml:canvas')
.attr('xmlns', 'http://www.w3.org/1999/xhtml');
const context = canvas.node().getContext('2d');
console.log(canvas.node().constructor.name);
// => HTMLCanvasElement
// Draw something
context.fillStyle = 'blue';
context.fillRect(0, 0, 100, 100);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
名称空间的概念不容易理解,并且大多数时候您不需要显式设置它们,因为它们是从父元素继承的。 Mike Bostock在this Github issue中很好地解释了这个概念。
(是的,我打开了问题,它也不知道如何使用名称空间。)