我有一个SVG图表,并且y轴是使用负像素位置创建的。这使我应用了变换并将图表平移35px以补偿负位置。这样做会切断我数据的最后一部分。我该如何重新排列以便所有数据都适合容器?
我曾尝试将y轴标签分离到自己的svg中,并使用flexbox将其放置在主数据svg旁边,但仍然看不到数据的突出部分。也许我还没有解决这个问题?
<div class="total-chart-wrapper" id="total-chart-wrapper">
<svg id="total-chart" height="285" width="100%">
<defs>
<linearGradient id="total-gradient" gradientTransform="rotate(90)">
<stop offset="0" stop-color="rgba(76, 150, 254, 1.00)"/>
<stop offset="0.5" stop-color="rgba(76, 150, 254, 0.70)"/>
<stop offset="1" stop-color="rgba(255, 255, 255, 0.000)"/>
</linearGradient>
</defs>
<g transform="translate(40,40)">
<g class="y axis" id="total-y-ticks">
<line class="y-axis-zero-line axis-line" id="y-axis-zero-line-total" x1="0" y1="0" x2="0" y2="240"></line>
</g>
<g><polygon id="total-chart-polygon" fill="url('#total-gradient')"></polygon></g>
<g class="x axis" id="total-x-ticks" transform="translate(0,0)">
<line class="x-axis-zero-line axis-line" id="x-axis-zero-line-total" x1="0" y1="240" x2="600" y2="240"></line>
</g>
</g>
</svg>
</div>
将所有代码都放在此处太长了,所以这里是一个功能性的数字笔:https://codepen.io/Finches/pen/eYYVEgW
如果您检查数据/多边形,您会在最后看到它切断了一些数据。
预期结果是将所有数据放入svg。 实际结果是不可见的数据突出,可能是由于对包含图表的g进行了变换。到目前为止,由于y标签中的负边距使它们位于图表原点的左侧,因此我无法解决此问题。有帮助吗?
答案 0 :(得分:1)
您的父div设置为600像素。 因此,父级太小而无法容纳SVG。 通过使用transform,您还将SVG进一步推向了包装。
.total-chart-wrapper {
width: 600px;
}
更改为:
.total-chart-wrapper {
width: auto;
}
它将正常工作(它将选择SVG宽度)
答案 1 :(得分:1)
在Javascript中,如下更改const totalChartWidth
:
const totalChartWidth = document.getElementById('total-chart-wrapper').offsetWidth - 50;
- 50
会在左侧给您50px,并将您的图表完全放在600px的父分区中。
您可以将此- 50
更改为一些代码,该代码可以动态计算此分隔符的数量,以使其响应更快。
请记住,尽管代码的设置方式是仅在页面加载时获得这些值,所以图表不会对窗口的简单调整大小做出响应。调整大小后,需要刷新页面,以便您看到效果。
// Total bar container width 35 px
// Labels before formatting
const labels = [
['Wed', '11 PM'],
['Thu', '12 AM'],
['Thu', '1 AM'],
['Thu', '2 AM'],
['Thu', '3 AM'],
['Thu', '4 AM'],
['Thu', '5 AM'],
['Thu', '6 AM'],
['Thu', '7 AM'],
['Thu', '8 AM'],
['Thu', '9 AM'],
['Thu', '10 AM'],
['Thu', '11 AM'],
['Thu', '12 PM'],
['Thu', '1 PM'],
['Thu', '2 PM'],
['Thu', '3 PM'],
['Thu', '4 PM'],
['Thu', '5 PM'],
['Thu', '6 PM'],
['Thu', '7 PM'],
['Thu', '8 PM'],
['Thu', '9 PM'],
['Thu', '10 PM'],
['Thu', '11 PM'],
['Fri', '12 AM'],
['Fri', '1 AM'],
['Fri', '2 AM'],
['Fri', '3 AM'],
['Fri', '4 AM'],
['Fri', '5 AM'],
];
// Data points
const data = [
0.25,
0.56,
0.5,
0.5,
0.86,
0.45,
0.3,
0,
0.3,
0.6,
0.4,
0,
0,
0.8,
0,
0,
0.4,
0.3,
0.1,
0,
0,
0.2,
0,
0,
0.4,
0.7,
0.1,
0.6,
0.4,
0.6,
0.4,
];
// Function to figure out max Y Tick
function yAxisRangeImperial(max) {
if (max < 1) {
return 1;
} else if (max < 2) {
return 2;
} else if (max < 4) {
return 4;
} else if (max < 8) {
return 8;
} else if (max < 12) {
return 12;
} else if (max < 24) {
return 24;
} else if (max < 48) {
return 48;
} else if (max < 72) {
return 72;
} else if (max < 96) {
return 96;
} else {
return 192;
}
};
// Area chart
// Sum of all snowfall
const maxTotalValue = data.reduce(function(acc, val) { return acc + val; }, 0);
// Getting chart components by ID
const totalChart = document.getElementById('total-chart');
const totalXAxis = document.getElementById('total-x-ticks');
const totalYAxis = document.getElementById('total-y-ticks');
const totalPolygon = document.getElementById('total-chart-polygon');
const totalChartWidth = document.getElementById('total-chart-wrapper').offsetWidth - 50;
// Function to determine hour display interval
function hoursLabelTotalInterval(hours) {
if (hours <= 6) {
return 1;
} else if (hours <= 12) {
return 2;
} else if (hours <= 24) {
return 4;
} else if (hours <= 36) {
return 6;
} else if (hours <= 48) {
return 8;
} else if (hours <= 60) {
return 10;
} else if (hours <= 72) {
return 12;
} else {
return 24;
}
}
// Function to create x axis labels
function createTotalLabels(labels) {
const hoursInterval = hoursLabelTotalInterval(labels.length);
let spacing = totalChartWidth/labels.length;
let currentDay = '';
const formattedLabels = labels.map((label, i) => {
if (i % hoursInterval === 0) {
if (label[0] !== currentDay) {
currentDay = label[0];
return [label[0], label[1]]
}
return ['', label[1]]
}
return ['','']
});
for (let i=0; i<formattedLabels.length; i++) {
let translateDistance;
if (i === 0) {
translateDistance = 15;
} else {
translateDistance = i*spacing + 15;
}
if (formattedLabels[i][1].length && i !== 0) {
totalXAxis.innerHTML +=
'<g class="tick" transform="translate(' + translateDistance + ',0)"><line class="y-axis-zero-line axis-line dash gray" stroke-dasharray="4" stroke-width="1" x1="-13" y1="0" x2="-13" y2="240"></line><text class="label-day" dy=".71em" y="-20" x="0">' + formattedLabels[i][0] + '</text><text class="label-time" dy=".71em" y="-10" x="0">' + formattedLabels[i][1] + '</text></g>';
} else {
totalXAxis.innerHTML +=
'<g class="tick" transform="translate(' + translateDistance + ',0)"><text class="label-day" dy=".71em" y="-20" x="0">' + formattedLabels[i][0] + '</text><text class="label-time" dy=".71em" y="-10" x="0">' + formattedLabels[i][1] + '</text></g>';
}
}
}
// Function to populate the y axis ticks and depth labels for total accumulation
function populateHourlyYAxisLabelsTotal(max, unit) {
let maxYTick = yAxisRangeImperial(max);
let tickContainer = document.getElementById('total-y-ticks');
// Get x axis zero line
let xAxisZeroLine = document.getElementById('x-axis-zero-line-total');
let interval = maxYTick / 4;
let ticks = [
interval + unit,
interval * 2 + unit,
interval * 3 + unit,
interval * 4 + unit,
];
let width = totalChartWidth;
let height = 240;
tickContainer.innerHTML += '<line class="gray" x2="-30" y2="0"></line><line class="gray" x1="0" x2="' + width + '" y2="0"></line>';
xAxisZeroLine.setAttribute("x2", width);
for (let j=ticks.length-1; j>=0; j--) {
if (j !== 0) {
tickContainer.innerHTML += '<g class="tick" transform="translate(0,'+ (height - (60*j)) +')"><line class="gray" x2="-30" y2="0"></line><line class="gray" x1="0" x2="' + width + '" y2="0"></line><text class="y-tick" dy=".32em" x="-9" y="-30" style="text-anchor: end;">'+ ticks[j] +'</text></g>'
} else {
tickContainer.innerHTML += '<g class="tick" transform="translate(0,'+ height +')"><line x2="-30" y2="0"></line><text dy=".32em" x="-9" y="-30" style="text-anchor: end;">'+ ticks[j] +'</text></g>'
}
};
};
// Function to create area of accumulation
function accumulationAreaPoints(data, max) {
let spacing = totalChartWidth/data.length;
let maxYTick = yAxisRangeImperial(max);
let summedDataSet = data.map(Number);
summedDataSet = summedDataSet.map((elem, index) => summedDataSet.slice(0, index + 1).reduce((a, b) => a + b));
summedDataSet = summedDataSet.map(function(each_element) {
return Number(each_element.toFixed(2));
});
summedDataSet.unshift(0);
for (let i=0; i<summedDataSet.length; i++) {
let point = totalChart.createSVGPoint();
let yLocation = (1 - summedDataSet[i]/maxYTick) * 240;
point.x = spacing*i;
point.y = yLocation;
totalPolygon.points.appendItem(point);
}
let finalPoint = totalChart.createSVGPoint();
finalPoint.x = summedDataSet.length*spacing - spacing;
finalPoint.y = 240;
totalPolygon.points.appendItem(finalPoint);
}
createTotalLabels(labels);
populateHourlyYAxisLabelsTotal(maxTotalValue, '"');
accumulationAreaPoints(data, maxTotalValue);
window.addEventListener('resize', populateHourlyYAxisLabelsTotal(maxTotalValue, '"'));
window.addEventListener('resize', accumulationAreaPoints(data, maxTotalValue));
h1 {
font: 24px sans-serif;
}
.bar {
fill: #4a93ff;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
body {
font-family: 'Open Sans', sans-serif !important;
}
.axis-line {
stroke-width: 1px;
}
.tick {
opacity: 1;
}
.tick text {
text-anchor: middle;
font-family: 'Open Sans', sans-serif;
}
.tick line.gray, line.gray {
stroke: #d9d9d9;
}
.label-day, .y-tick {
font-weight: bold;
}
.label-time {
font-weight: normal;
}
.total-chart-wrapper {
width: 600px;
}
<link href="https://fonts.googleapis.com/css?family=Open+Sans&display=swap" rel="stylesheet">
<div class="total-chart-wrapper" id="total-chart-wrapper">
<svg id="total-chart" height="285" width="100%">
<defs>
<linearGradient id="total-gradient" gradientTransform="rotate(90)">
<stop offset="0" stop-color="rgba(76, 150, 254, 1.00)"/>
<stop offset="0.5" stop-color="rgba(76, 150, 254, 0.70)"/>
<stop offset="1" stop-color="rgba(255, 255, 255, 0.000)"/>
</linearGradient>
</defs>
<g transform="translate(40,40)">
<g class="y axis" id="total-y-ticks">
<line class="y-axis-zero-line axis-line" id="y-axis-zero-line-total" x1="0" y1="0" x2="0" y2="240"></line>
</g>
<g><polygon id="total-chart-polygon" fill="url('#total-gradient')"></polygon></g>
<g class="x axis" id="total-x-ticks" transform="translate(0,0)">
<line class="x-axis-zero-line axis-line" id="x-axis-zero-line-total" x1="0" y1="240" x2="600" y2="240"></line>
</g>
</g>
</svg>
</div>