弄了一個範例給樓主參考,網址如下:
http://www.web3d.url.tw/ITHELP/D3_20191220/
左邊是原圖,右邊是y值介於2500-3000的內容會顯示在y座標中間60%的區域)
源碼:
<!DOCTYPE html>
<html lang="zh-tw">
<head>
<meta charset="utf-8">
<title>絕對座標轉相對座標測試</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Audiowide&display=swap" rel="stylesheet">
<style>*,html{margin:0;padding:0;}body{background:#fff;font-family: 'Audiowide', cursive;}svg{background:#ffd;border:Solid 1px #999;} circle{opacity:0.5;}</style>
</head>
<body onload="draw()">
<svg id="svg1"></svg>
<svg id="svg2"></svg>
<script>
function draw() {
d3.tsv("demo-data.tsv")
.then(function (data){
console.log(data);
const padding=20;
const pxX = (window.innerWidth-padding)/2;
const pxY = window.innerHeight-padding;
const scX = d3.scaleLinear()
.domain(d3.extent(data, d => d.x))
.range([0+padding, pxX-padding]);
const scY = d3.scaleLinear()
.domain(d3.extent(data, d => d.y))
.range([pxY-padding, 0+padding]);
let scYFix = (yVal) =>{
const maxValue=5000,minValue=0,valueGap=1000;
const valueIn90percent=maxValue-valueGap;
const valueIn10percent=minValue+valueGap;
if(yVal>2499&&yVal<3001){
//介於2500至3000之間
return valueGap+((yVal-2500)/500)*3000;
}else if(yVal>3000){
//大於3000
return valueIn90percent+((yVal-3000)/2000)*valueGap;
}else{
//小於2500
return (yVal/2500)*valueGap;
}
};
let svg1=d3.select('#svg1').attr('width',pxX).attr('height',pxY);
svg1.selectAll('line').data(data).enter().append('line').
attr('x1',0).attr('x2',pxX).attr('y1',d=>scY(d.y)).attr('y2',d=>scY(d.y))
.attr('stroke',d=>{return (d.y>2499&&d.y<3001)?'Red':'Green';}).attr('stroke-dasharray','5,5');
svg1.selectAll('circle').data(data).enter().append('circle')
.attr("r",d=>{return (d.y>2499&&d.y<3001)?20:5;})
.attr('fill',d=>{return (d.y>2499&&d.y<3001)?'Red':'Green';})
.attr('cx',d=>scX(d.x)).attr('cy',d=>scY(d.y));
svg1.selectAll('text').data(data).enter().append('text')
.attr('x',d=>scX(d.x>0?d.x-0.5:d.x+0.1)).attr('y',d=>scY(d.y)).text(d=>d.y);
let svg2=d3.select('#svg2').attr('width',pxX).attr('height',pxY);
svg2.selectAll('line').data(data).enter().append('line')
.attr('x1',0).attr('x2',pxX).attr('y1',d=>scY(scYFix(d.y)))
.attr('y2',d=>scY(scYFix(d.y)))
.attr('stroke',d=>{return (d.y>2499&&d.y<3001)?'Red':'Green';}).attr('stroke-dasharray','5,5');
svg2.selectAll('circle').data(data).enter().append('circle')
.attr("r",d=>{return (d.y>2499&&d.y<3001)?20:5;})
.attr('fill',d=>{return (d.y>2499&&d.y<3001)?'Red':'Green';})
.attr('cx',d=>scX(d.x)).attr('cy',d=>scY(scYFix(d.y)));
svg2.selectAll('text').data(data).enter().append('text')
.attr('x',d=>scX(d.x>0?d.x-0.5:d.x+0.1)).attr('y',d=>scY(scYFix(d.y))).text(d=>d.y);
})
}
</script>
</body></html>
資料源 demo-data.tsv 內容為:
x y
0 0
1 350
2 1500
3 2520
4 2990
5 2780
6 3500
7 4350
8 5000
整理一下樓主問的大概是說 假如Y值如果落在2500~3000範圍內的部份要局部放大,
其它的部份(>3000或<2500)則相對的要縮小,但是同時要維持原本的比例。
這個部份我不是在scaleLinear()處理,而是另外寫一個函式去把y依照設定的條件把絕對座標轉換為相對座標,詳情請參閱上面的源碼。