deepsite-project / wellbore-schematic.js
Akshaymakhare's picture
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 />);
```