Skip to content

Instantly share code, notes, and snippets.

@bfunc
Last active October 9, 2017 12:31
Show Gist options
  • Save bfunc/9640511725a77d677d4ed2405d2832e3 to your computer and use it in GitHub Desktop.
Save bfunc/9640511725a77d677d4ed2405d2832e3 to your computer and use it in GitHub Desktop.
d3 v4 - issue - axis Date grid uneven line sizes
[
{
"daystamp": {
"value": "2017-03-01 00:00:00.000"
},
"PL": -13496
},
{
"daystamp": {
"value": "2017-03-02 00:00:00.000"
},
"PL": -9930
},
{
"daystamp": {
"value": "2017-03-07 00:00:00.000"
},
"PL": -11506
},
{
"daystamp": {
"value": "2017-03-08 00:00:00.000"
},
"PL": -1970
},
{
"daystamp": {
"value": "2017-03-09 00:00:00.000"
},
"PL": 336
},
{
"daystamp": {
"value": "2017-03-10 00:00:00.000"
},
"PL": 7024
},
{
"daystamp": {
"value": "2017-03-13 00:00:00.000"
},
"PL": 5876
},
{
"daystamp": {
"value": "2017-03-14 00:00:00.000"
},
"PL": 4584
},
{
"daystamp": {
"value": "2017-03-16 00:00:00.000"
},
"PL": 6448
},
{
"daystamp": {
"value": "2017-03-17 00:00:00.000"
},
"PL": 5782
},
{
"daystamp": {
"value": "2017-03-20 00:00:00.000"
},
"PL": 5528
},
{
"daystamp": {
"value": "2017-03-23 00:00:00.000"
},
"PL": 9470
},
{
"daystamp": {
"value": "2017-03-24 00:00:00.000"
},
"PL": 7328
},
{
"daystamp": {
"value": "2017-03-27 00:00:00.000"
},
"PL": 7482
},
{
"daystamp": {
"value": "2017-03-28 00:00:00.000"
},
"PL": 6890
},
{
"daystamp": {
"value": "2017-03-30 00:00:00.000"
},
"PL": -42
},
{
"daystamp": {
"value": "2017-04-03 00:00:00.000"
},
"PL": -2006
},
{
"daystamp": {
"value": "2017-04-04 00:00:00.000"
},
"PL": -6590
},
{
"daystamp": {
"value": "2017-04-05 00:00:00.000"
},
"PL": -5348
},
{
"daystamp": {
"value": "2017-04-07 00:00:00.000"
},
"PL": -10012
},
{
"daystamp": {
"value": "2017-04-10 00:00:00.000"
},
"PL": -13742
},
{
"daystamp": {
"value": "2017-04-11 00:00:00.000"
},
"PL": -16128
},
{
"daystamp": {
"value": "2017-04-12 00:00:00.000"
},
"PL": -14426
},
{
"daystamp": {
"value": "2017-04-13 00:00:00.000"
},
"PL": -14036
},
{
"daystamp": {
"value": "2017-04-17 00:00:00.000"
},
"PL": -14956
},
{
"daystamp": {
"value": "2017-04-18 00:00:00.000"
},
"PL": -12734
},
{
"daystamp": {
"value": "2017-04-19 00:00:00.000"
},
"PL": -4370
},
{
"daystamp": {
"value": "2017-04-20 00:00:00.000"
},
"PL": -3428
},
{
"daystamp": {
"value": "2017-04-21 00:00:00.000"
},
"PL": 728
},
{
"daystamp": {
"value": "2017-04-24 00:00:00.000"
},
"PL": 1722
},
{
"daystamp": {
"value": "2017-04-25 00:00:00.000"
},
"PL": -372
},
{
"daystamp": {
"value": "2017-04-26 00:00:00.000"
},
"PL": 2864
},
{
"daystamp": {
"value": "2017-04-27 00:00:00.000"
},
"PL": 2300
}
]
<html>
<head>
<title>Chart!</title>
<script src="https://d3js.org/d3.v4.min.js" type="text/javascript" charset="utf-8"></script>
<style>
svg#chart {
background-color: #E0E0E0;
position: absolute;
}
svg#chart path.link {
fill: none;
stroke-width: 4px;
stroke: #4D4D4D;
}
svg#chart .tick line {
stroke: #868686;
stroke-opacity: 0.5;
shape-rendering: crispEdges;
}
svg#chart #cipping-mask-rect-bg {
fill: #FFFFFF;
}
svg#chart .tick path {
stroke-width: 0;
}
</style>
</head>
<body>
<svg id='chart'>
<defs>
<clipPath id='cipping-mask'>
<rect id='cipping-mask-rect' x='0' y='0' width='100' height='100' />
</clipPath>
</defs>
<rect id='cipping-mask-rect-bg' x='0' y='0' width='100' height='100' />
<g id='controls-group' />
<g id='chart-group' clip-path='url(#cipping-mask)' />
</svg>
<script>
const
OFFSET_CHART_X = 50,
OFFSET_CHART_Y = 25;
window.d3 = d3;
/// init vars //////////////////
d3.json("data.json", function (error, json) {
if (error) throw error;
init(json);
});
function init(jsonData) {
let svg = d3.select('svg#chart'),
controlsGroup = svg.select('g#controls-group'),
chartGroup = svg.select('g#chart-group')
.attr('transform', `translate(${OFFSET_CHART_X},${OFFSET_CHART_Y})`),
mask = d3.select('rect#cipping-mask-rect'),
maskBg = d3.select('rect#cipping-mask-rect-bg')
.attr('transform', `translate(${OFFSET_CHART_X},${OFFSET_CHART_Y})`),
xScale, yScale, xAxisG, yAxisG, xScaleUpdated,
width = 750, height = 450,
data = jsonData.map(v => ({ date: new Date(v.daystamp.value), value: +v.PL })),
formatTime = d3.timeFormat('%B %d, %Y'),
lineGenerator = d3.line()
.x(d => xScale(d.date))
.y(d => yScale(d.value))
.curve(d3.curveLinear);
/// layout ////////////////////
svg.attr('width', width);
svg.attr('height', height);
let maskWidth = width - OFFSET_CHART_X * 2;
let maskHeight = height - OFFSET_CHART_Y * 3;
mask.attr('width', maskWidth);
mask.attr('height', maskHeight);
maskBg.attr('width', maskWidth);
maskBg.attr('height', maskHeight);
updateAxis();
/// d3 enter/update ///////////////
let chart = chartGroup.selectAll('path')
.data([data]);
let grpChartEnter = chart.enter()
.append('path')
.attr('class', 'link');
chart = grpChartEnter.merge(chart)
.attr('d', lineGenerator);
/// zoom ///////////////////////////
let zoom = d3.zoom().on('zoom', zoomFnc);
svg.call(zoom);
zoom.scaleTo(svg, 2)
/// helper functions ///////////////
function zoomFnc() {
xAxisG.transition()
.duration(1)
.call(xAxis.ticks(10).scale(d3.event.transform.rescaleX(xScale)));
let
new_xScale = d3.event.transform.rescaleX(xScale),
new_lineGenerator = d3.line()
.x(d => new_xScale(d.date))
.y(d => yScale(d.value));
chart.attr('d', new_lineGenerator);
xScaleUpdated = new_xScale;
}
function updateAxis() {
controlsGroup.selectAll('g.axisX').remove();
controlsGroup.selectAll('g.axisY').remove();
xScale = d3.scaleTime().range([0, width - OFFSET_CHART_X * 2]);
xScale.domain(expandDateByTs(d3.extent(data, d => d.date)));
xAxis = d3.axisBottom(xScale);
xAxisG = controlsGroup.append('g')
.attr('class', 'axisX')
.attr('transform', `translate(${OFFSET_CHART_X},${height - OFFSET_CHART_Y * 2} )`)
.call(xAxis);
xScaleUpdated = xScale;
yScale = d3.scaleLinear().range([height - OFFSET_CHART_Y * 3, 0]);
yScale.domain(expandByPercent(d3.extent(data, d => d.value), 10));
yAxis = d3.axisLeft(yScale);
yAxisG = controlsGroup.append('g')
.attr('class', 'axisY')
.attr('transform', `translate(${OFFSET_CHART_X},${OFFSET_CHART_Y})`)
.call(yAxis);
// Gridline
let gridlinesX = xAxis
.ticks()
.tickSize(-(height - OFFSET_CHART_Y * 3))
.scale(xScale)
xAxisG.call(gridlinesX);
let gridlinesY = yAxis
.ticks()
.tickSize(-(width - OFFSET_CHART_X * 2))
.scale(yScale)
yAxisG.call(gridlinesY);
function expandByPercent(arr, percent) {
let val1 = arr[0], val2 = arr[1],
val1p = val1 * (percent / 100),
val2p = val2 * (percent / 100);
return [val1 + val1p, val2 + val2p];
}
function expandDateByTs(arr, day = 1000 * 60 * 60 * 24) {
let val1 = Date.parse(arr[0]), val2 = Date.parse(arr[1]);
return [val1 - day, val2 + day];
}
}
//////////////////////////////////////////
}// end of init function
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment