Consider the following example, test.html, which is my simplified modification of https://observablehq.com/@d3/pan-zoom-axes?collection=@d3/d3-zoom tested on latest Firefox 104 on both Windows and Linux:
<!doctype html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js" charset="utf-8"></script>
<style type="text/css">
</style>
<!-- script type module raises CORS Cross-Origin Request Blocked,
when used locally (implied file://..js)
<script type="module">
import {zoom} from "https://cdn.skypack.dev/d3-zoom@3";
console.log(zoom);
//const handler = zoom();
import {svg} from "https://cdn.skypack.dev/htl@0.3.1";
console.log(svg);
</script> -->
<script src="https://cdn.jsdelivr.net/npm/d3-zoom@3"></script>
<script src="https://cdn.jsdelivr.net/npm/htl@0.3.1"></script>
</head>
<body>
<div>
<h3>Test</h3>
<div id="viewer"></div>
</div>
<script type="text/javascript" charset="utf-8">
var vbWidth = 400;
var vbHeight = 100;
const svg = d3.select("#viewer")
.style("background-color", "green")
.append("svg")
.attr("viewBox", [0, 0, vbWidth, vbHeight]);
defs = () => htl.svg`<defs>
<style>
/*.axis .domain { display: none; }*/
.axis line { stroke-opacity: 0.3; shape-rendering: crispEdges; stroke-width: 0.4px; }
/*.view { fill: url(#gradient); stroke: #000; }*/
.view { fill: white; stroke: #000; shape-rendering: crispEdges; }
.axis text { font-size: 4px; }
</style>
`
svg.append(defs);
const view = svg.append("rect")
.attr("class", "view")
.attr("x", 0) // 0.5)
.attr("y", 0) // 0.5)
.attr("width", vbWidth)
.attr("height", vbHeight-30);
x = d3.scaleLinear()
.domain([0, 100]) // "[0, 100] This is what is written on the Axis: from 0 to 100"
.range([0, vbWidth]); // "[100, 800] This is where the axis is placed: from 100px to 800px"
xAxis = d3.axisBottom(x)
.ticks(((vbWidth + 2) / (vbHeight + 2)) * 10)
.tickSize(vbHeight)
.tickPadding(-28)
;
y = d3.scaleLinear()
.domain([-1, vbHeight + 1])
.range([-1, vbHeight + 1]);
yAxis = d3.axisRight(y)
.ticks(10)
.tickSize(vbWidth)
.tickPadding(8 - vbWidth)
;
const gX = svg.append("g").attr("class", "axis axis--x").call(xAxis);
const gY = svg.append("g").attr("class", "axis axis--y").call(yAxis);
function zoomed({ transform }) {
view.attr("transform", transform);
const newsw = ((1.0/transform.k));
view.attr("stroke-width", newsw+"px") // https://bl.ocks.org/rgdonohue/51c43bb749689e696b8a
console.log("k", transform.k, "n", newsw);
gX.call(xAxis.scale(transform.rescaleX(x)));
gY.call(yAxis.scale(transform.rescaleY(y)));
//svg.selectAll(".tick text")
gX.selectAll("text")
.attr("transform-origin", "top left")
.style("text-anchor", "end")
//.attr("dx", "-1.8em")
//.attr("dy", "1.15em")
.attr("transform", function(d) {
//console.log(d); // numbers - coords
//return d3.select(this).attr("transform") + " rotate(10)"; // SO:17791926
//console.log(d3.select(this).attr("transform")); // null! or "rotate(45)" if already set once
return "rotate(45)";
})
;
} // end function zoomed
const zoom = d3.zoom()
.scaleExtent([1, 40]) // min and max zoom level
.translateExtent([[-100, -100], [vbWidth + 90, vbHeight + 100]])
.filter(filter)
.on("zoom", zoomed);
Object.assign(svg.call(zoom).node(), {reset});
function reset() {
svg.transition()
.duration(750)
.call(zoom.transform, d3.zoomIdentity);
}
// prevent scrolling then apply the default filter
function filter(event) {
console.log("filter", event);
event.preventDefault();
return (!event.ctrlKey || event.type === 'wheel') && !event.button;
}
</script>
</body>
</html>
I have two problems here:
Note that I have attempted to keep the stroke width the same across zoom levels with the
const newsw = ((1.0/transform.k)); however, if I zoom in with the mousewheel to a larger zoom level, I randomly get jagged edges (or edges disappear) of the white rectangle, upon repeated zoom-in/zoom-out:

If I do not rotate the tick labels (the line
return "rotate(45)";is commented), then labels keep their position fine upon dragging (as the above animated image shows). however, if I enable it - the labels are off their intended location:

So, with this problem, the origin of the white rectangle can be read to be (14,0) from the tick labels - instead of the correct (0,0).
So, what needs to be changed in the code, so I both have correctly rendered constant stroke width (here, of the white rectangle), regardless of zoom level and drag position - and I have rotated tick labels, which are correctly positioned, even when dragging and zooming?