Spaces:
Running
Running
I'll help you create a TypeScript project that visualizes the wellbore schematic based on your Excel data. This will display the well path, casing strings, and formations similar to your image.
9ee9831 verified | ```javascript | |
| const WellboreSchematic = () => { | |
| const svgRef = React.useRef(null); | |
| // Data from Excel sheet | |
| const casingData = [ | |
| { | |
| name: "30in Casing", | |
| diameter: 30, | |
| startMD: 38.25, | |
| endMD: 180, | |
| startTVD: 38.25, | |
| endTVD: 180 | |
| }, | |
| { | |
| name: "20in Casing", | |
| diameter: 20, | |
| startMD: 38.25, | |
| endMD: 308, | |
| startTVD: 38.25, | |
| endTVD: 306.66 | |
| }, | |
| { | |
| name: "13.375in Casing", | |
| diameter: 13.375, | |
| startMD: 38.25, | |
| endMD: 1676, | |
| startTVD: 38.25, | |
| endTVD: 991.38 | |
| }, | |
| { | |
| name: "9.625in Casing", | |
| diameter: 9.625, | |
| startMD: 38.25, | |
| endMD: 2920, | |
| startTVD: 38.25, | |
| endTVD: 1335.63 | |
| } | |
| ]; | |
| const formations = [ | |
| { name: "Top Shale", topDepth: 365.76 }, | |
| { name: "Sand A", topDepth: 914.4 } | |
| ]; | |
| const target = { | |
| name: "A2-VII-Target", | |
| tvd: 1372.25 | |
| }; | |
| const maxDepth = 3215; | |
| const maxTVD = 1416.49; | |
| React.useEffect(() => { | |
| if (!svgRef.current) return; | |
| const svg = d3.select(svgRef.current); | |
| svg.selectAll("*").remove(); | |
| const width = 800; | |
| const height = 600; | |
| const margin = { top: 60, right: 120, left: 120, bottom: 60 }; | |
| const chartWidth = width - margin.left - margin.right; | |
| const chartHeight = height - margin.top - margin.bottom; | |
| const depthScale = d3.scaleLinear() | |
| .domain([0, maxTVD]) | |
| .range([0, chartHeight]); | |
| const diameterScale = d3.scaleLinear() | |
| .domain([0, 30]) | |
| .range([0, 80]); | |
| const g = svg.append("g") | |
| .attr("transform", `translate(${margin.left},${margin.top})`); | |
| // Draw wellbore and casing strings | |
| g.append("line") | |
| .attr("x1", chartWidth / 2) | |
| .attr("y1", 0) | |
| .attr("x2", chartWidth / 2) | |
| .attr("y2", chartHeight) | |
| .attr("stroke", "#333") | |
| .attr("stroke-width", 2); | |
| casingData.forEach((casing, index) => { | |
| const casingGroup = g.append("g"); | |
| const casingWidth = diameterScale(casing.diameter); | |
| const yStart = depthScale(casing.startTVD); | |
| const yEnd = depthScale(casing.endTVD); | |
| const height = yEnd - yStart; | |
| casingGroup.append("rect") | |
| .attr("x", chartWidth / 2 - casingWidth / 2) | |
| .attr("y", yStart) | |
| .attr("width", casingWidth) | |
| .attr("height", height) | |
| .attr("fill", index % 2 === 0 ? "#e0e0e0" : "#f0f0f0") | |
| .attr("stroke", "#666") | |
| .attr("stroke-width", 1); | |
| casingGroup.append("text") | |
| .attr("x", chartWidth / 2 + casingWidth / 2 + 10) | |
| .attr("y", yStart + height / 2) | |
| .attr("dy", "0.35em") | |
| .style("font-size", "10px") | |
| .text(`${casing.diameter}" Casing`); | |
| }); | |
| // Draw formations | |
| formations.forEach(formation => { | |
| const y = depthScale(formation.topDepth); | |
| g.append("line") | |
| .attr("x1", chartWidth / 2 - 40) | |
| .attr("y1", y) | |
| .attr("x2", chartWidth / 2 + 40) | |
| .attr("y2", y) | |
| .attr("stroke", "#8B4513") | |
| .attr("stroke-width", 2) | |
| .attr("stroke-dasharray", "5,5"); | |
| g.append("text") | |
| .attr("x", chartWidth / 2 + 50) | |
| .attr("y", y) | |
| .attr("dy", "0.35em") | |
| .style("font-size", "10px") | |
| .text(`${formation.name} (${Math.round(formation.topDepth)}m)`); | |
| }); | |
| // Draw target | |
| const targetY = depthScale(target.tvd); | |
| g.append("circle") | |
| .attr("cx", chartWidth / 2) | |
| .attr("cy", targetY) | |
| .attr("r", 6) | |
| .attr("fill", "red"); | |
| g.append("text") | |
| .attr("x", chartWidth / 2 + 15) | |
| .attr("y", targetY) | |
| .attr("dy", "0.35em") | |
| .style("font-size", "10px") | |
| .text(`${target.name}`); | |
| }, []); | |
| return ( | |
| <div style={{ padding: '20px' }}> | |
| <svg | |
| ref={svgRef} | |
| width={800} | |
| height={600} | |
| style={{ border: '1px solid #ccc', background: 'white' }} | |
| /> | |
| <div style={{ marginTop: '20px', fontSize: '12px', color: '#666' }}> | |
| <p><strong>Well:</strong> N-11#12 | <strong>Field:</strong> Mumbai High North</p> | |
| <p><strong>Total Depth:</strong> {maxDepth}m MD / {maxTVD.toFixed(2)}m TVD</p> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| const root = ReactDOM.createRoot(document.getElementById('root')); | |
| root.render(<WellboreSchematic />); | |
| ``` |