Files
vscode-debug-visualizer/webview/src/visualizers/SvgVisualizer.tsx
2020-02-29 21:31:22 +01:00

117 lines
2.5 KiB
TypeScript

import Measure, { ContentRect } from "react-measure";
import { observer } from "mobx-react";
import React = require("react");
import { observable, action } from "mobx";
import { Tool, ReactSVGPanZoom, Value } from "react-svg-pan-zoom";
import {
VisualizationProvider,
VisualizationCollector,
asVisualizationId,
} from "./Visualizer";
import {
ExtractedData,
isCommonDataType,
} from "@hediet/debug-visualizer-data-extraction";
export class SvgVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
if (isCommonDataType(data, { svg: true })) {
collector.addVisualization({
id: asVisualizationId("svg"),
name: "Svg",
priority: 100,
render() {
return <SvgViewer svgContent={data.text} />;
},
});
}
}
}
function widthOrDefault(r: ContentRect): number {
if (r.bounds && r.bounds.width) {
return r.bounds.width;
}
return 1;
}
function heightOrDefault(r: ContentRect): number {
console.log(r);
if (r.bounds && r.bounds.height) {
return r.bounds.height;
}
return 1;
}
@observer
export class SvgViewer extends React.Component<{
svgContent: string;
svgRef?: (element: SVGSVGElement | null) => void;
}> {
@observable tool: Tool = "pan";
@action.bound
private setTool(tool: Tool): void {
this.tool = tool;
}
private setRef(element: ReactSVGPanZoom | null) {
if (this.props.svgRef) {
if (!element) {
this.props.svgRef(null);
return;
}
const svg = (element as any).ViewerDOM as SVGSVGElement;
this.props.svgRef(svg);
}
}
@observable value: Value | {} = {};
render() {
let { svgContent } = this.props;
let width: number = 0;
let height: number = 0;
svgContent = svgContent.replace(
/viewBox="[0-9\.]+ [0-9\.]+ ([0-9\.]+) ([0-9\.]+)"/,
(r, w, h) => {
width = parseFloat(w);
height = parseFloat(h);
return "";
}
);
const tool = this.tool;
const val = this.value;
return (
<Measure bounds>
{({ measureRef, contentRect }) => (
<div ref={measureRef} className="svgViewer">
<ReactSVGPanZoom
width={widthOrDefault(contentRect)}
height={heightOrDefault(contentRect)}
tool={tool}
value={val as any}
onChangeValue={v => (this.value = v)}
onChangeTool={this.setTool}
ref={e => this.setRef(e)}
>
<svg width={width} height={height}>
<g
dangerouslySetInnerHTML={{
__html: svgContent,
}}
/>
</svg>
</ReactSVGPanZoom>
</div>
)}
</Measure>
);
}
}