如何将用JSX创建的SVG元素用作Canvas中的图像源? [英] How can I use an SVG element created with JSX as an image source in a Canvas?
问题描述
我有一个ReactJS应用程序.我正在动态生成SVG图像作为JSX组件.到目前为止,一切都很好-但现在我需要将SVG用作Canvas元素中的图像源.这对于静态SVG文件可以很好地工作,但是如何将动态SVG放入画布?
I have a ReactJS application. I'm dynamically generating SVG images as JSX components. So far, so good -- but now I need to use the SVG as an image source in a Canvas element. This works fine with static SVG files, but how can I get the dynamic SVG into the canvas?
该代码段中出现一个简化的版本.在componentDidMount方法中显示了对drawImage调用的两种方法:创建一个未安装的SvgSource,并使用对页面上已安装的一个的引用,但它们均失败.
A simplified version appears in the snippet. Two approaches to the drawImage call are shown in the componentDidMount method: creating an unmounted SvgSource, and using a ref to one mounted on the page, but they both fail.
class App extends React.Component {
// On mount, paint the SVG in the canvas
componentDidMount(){
let ctx = this.canvasRef.getContext("2d")
// THIS DOES NOT WORK:
//ctx.drawImage(new SvgSource({fill: "green"}), 50, 50);
// NOR DOES THIS:
//ctx.drawImage(this.svgRef, 50, 50);
/* TypeError: Argument 1 of CanvasRenderingContext2D.drawImage could not be converted to any of: HTMLImageElement, SVGImageElement, HTMLCanvasElement, HTMLVideoElement, ImageBitmap. */
}
render() {
return (
<div>
{/* This works, inserting the SvgSource element directly - but that's not what I want. */}
<SvgSource ref={s => this.svgRef = s} fill="blue" />
{/* I want to use the SVG as an image source in this canvas. */}
<canvas
ref={
c => this.canvasRef = c
/* NB: using older ref syntax because jsFiddle uses React .14 - use CreateRef with version 16 */
}
width={200}
height={200} />
</div>
);
}
}
// Our JSX SVG component that provides the custom image to use in the canvas
class SvgSource extends React.Component {
render() {
return (
<svg width={100} height={100} viewBox="0 0 100 100">
<circle cx={50} cy={50} r={25} fill={this.props.fill || "red"}/>
</svg>
);
}
}
ReactDOM.render(<App />, document.querySelector("#app"))
body {
background: #20262E;
padding: 20px;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
min-height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
澄清一下:我知道如何将普通的SVG图像插入画布元素.问题在于将JSX SVG转换为画布上下文中drawImage
的有效源,以便可以在React组件中完成所有工作.
To clarify: I know how to insert ordinary SVG images into canvas elements. The problem is converting a JSX SVG into a valid source for a drawImage
on the canvas context, so that this can all be done in React components.
推荐答案
这不是很优雅的方法,但这是我最终得到的:
This is not a very graceful way to do it, but it's what I ended up with:
class SvgSource extends React.Component {
generateSvg() {
return "data:image/svg+xml;base64," +
btoa(`<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><circle cx="50" cy="50" r="25" fill="${this.props.fill}" /></svg>`);
}
render() {
return (<img src={this.generateSvg()} />);
}
}
我没有将SVG用作JSX对象,而是将其构造为字符串,并编码为base64以用作数据URL.然后,我可以从render()
函数返回一个<img>
JSX元素,以直接在页面中使用该图像.当我需要在画布上使用它时,可以在纯净的(非JSX)<img>
元素的src
属性中使用返回的字符串直接调用new SvgSource({fill: "green"}).generateSvg()
.
Instead of making the SVG a JSX object, I just construct it as a string, encoding to base64 for use as a data URL. I can then return an <img>
JSX element from the render()
function to use the image directly in the page. When I need to use it in a canvas, I can call new SvgSource({fill: "green"}).generateSvg()
directly, using the returned string in a plain (non-JSX) <img>
element's src
attribute.
如果没有将SVG标记真正放在页面上,我找不到更好的方法.
I could find no better way to get the SVG markup rendered without actually putting it on the page.
这篇关于如何将用JSX创建的SVG元素用作Canvas中的图像源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!