Мне кажется, что вы хотите адаптировать количество тиков к ширине, а не наоборот (подробнее об этом ниже). В этом случае вместо использования интервала, такого как d3.timeDay
, просто установите (приблизительное) число тиков:
axis.ticks(10)
Однако, если вы хотите изменить ширину SVG,Вы можете посчитать количество дней и установить ширину SVG соответственно:
var dayWidth = 30;//set the width for each day here
var numberOfDays = d3.timeDay.count(timeScale.domain()[0], timeScale.domain()[1]);//get the total number of days in the data
w = numberOfDays * dayWidth;
svg.attr("width", w);
Это просто быстрый код, чтобы вы могли увидеть, как вы можете это сделать, лучшее решение соответственно устанавливает поля (я несделать это, потому что в вашем коде много магических чисел).
Что касается высоты, вы можете рассчитать ее на основе количества задач и установить SVG соответственно:
h = tasks.length * gap + topPadding + 40;
svg.attr("height", h);
Имейте в виду, что у вас все еще есть магические числа здесь. Старайтесь избегать их.
Вот код с этими изменениями:
$(document).ready(function() {
myObj = JSON.parse('{"QUAL":[{"task": "milk", "type": "Ordered", "startTime": "14/10", "endTime": "16/11"},{"task": "butter", "type": "Completed", "startTime": "22/09", "endTime": "23/09"},{"task": "butter", "type": "Completed", "startTime": "24/09", "endTime": "25/09"},{"task": "bread", "type": "Completed", "startTime": "04/10", "endTime": "15/10"},{"task": "water", "type": "Completed", "startTime": "11/10", "endTime": "16/10"},{"task": "fish", "type": "Discontinued", "startTime": "21/09", "endTime": "23/09"},{"task": "mince", "type": "Discontinued", "startTime": "26/09", "endTime": "27/09"},{"task": "soda", "type": "Discontinued", "startTime": "04/10", "endTime": "08/10"},{"task": "sugar", "type": "Discontinued", "startTime": "04/10", "endTime": "08/10"},{"task": "flour", "type": "Discontinued", "startTime": "09/10", "endTime": "11/10"},{"task": "shampoo", "type": "Discontinued", "startTime": "10/10", "endTime": "11/10"},{"task": "salt", "type": "On Hold", "startTime": "04/10", "endTime": "04/10"}]}')
myObj2 = JSON.parse('{"QUAL":[{"task": "milk", "type": "Ordered", "startTime": "14/10", "endTime": "16/11"},{"task": "butter", "type": "Completed", "startTime": "22/09", "endTime": "23/09"},{"task": "butter", "type": "Completed", "startTime": "24/09", "endTime": "25/09"},{"task": "bread", "type": "Completed", "startTime": "04/10", "endTime": "15/10"},{"task": "water", "type": "Completed", "startTime": "11/10", "endTime": "16/10"},{"task": "fish", "type": "Discontinued", "startTime": "21/09", "endTime": "23/09"},{"task": "mince", "type": "Discontinued", "startTime": "26/09", "endTime": "27/09"}]}')
var taskArray = [];
$('.modal').on('hidden.bs.modal', function() {
document.getElementById("chart").innerHTML = ""
taskArray = [];
});
$('.modal').on('show.bs.modal', function() {
});
$('#btn1').on('click', function() {
$.each(myObj.QUAL, function(i, j) {
taskArray.push({
task: j.task,
type: j.type,
startTime: j.startTime,
endTime: j.endTime
})
})
makeChart();
});
$('#btn2').on('click', function() {
$.each(myObj2.QUAL, function(i, j) {
taskArray.push({
task: j.task,
type: j.type,
startTime: j.startTime,
endTime: j.endTime
})
})
makeChart();
});
makeChart = function() {
var w,
h,
dayWidth = 30;
$('#amsModal').modal({
backdrop: 'static'
});
// $('#amsDetailBodyImage').css('display', 'none');
var svg = d3.selectAll("#chart")
//.selectAll("svg")
.append("svg")
.attr("class", "svg");
//var dateFormat = d3.timeParse("%Y-%m-%d");
var dateFormat = d3.timeParse("%d/%m");
var timeScale = d3.scaleTime()
.domain([d3.min(taskArray, function(d) {
return dateFormat(d.startTime);
}),
d3.max(taskArray, function(d) {
return dateFormat(d.endTime);
})
]);
var numberOfDays = d3.timeDay.count(timeScale.domain()[0], timeScale.domain()[1]);
w = numberOfDays * dayWidth;
svg.attr("width", w);
timeScale.range([w - 150, 0]);
var categories = new Array();
for (var i = 0; i < taskArray.length; i++) {
categories.push(taskArray[i].type);
}
var catsUnfiltered = categories; //for vert labels
categories = checkUnique(categories);
makeGant(taskArray, w);
var title = svg.append("text")
.text("Groceries")
.attr("x", w / 2)
.attr("y", 25)
.attr("text-anchor", "middle")
.attr("font-size", 18)
.attr("fill", "#000000");
function makeGant(tasks, pageWidth) {
var barHeight = 20;
var gap = barHeight + 4;
var topPadding = 75;
var sidePadding = 75;
h = tasks.length * gap + topPadding + 40;
svg.attr("height", h);
var colorScale = d3.scaleLinear()
.domain([0, categories.length])
.range(["#00B9FA", "#F95002"])
.interpolate(d3.interpolateHcl);
makeGrid(sidePadding, topPadding, pageWidth, h);
drawRects(tasks, gap, topPadding, sidePadding, barHeight, colorScale, pageWidth, h);
vertLabels(gap, topPadding, sidePadding, barHeight, colorScale);
//$('.modal-button').attr('disabled', true);
}
function drawRects(theArray, theGap, theTopPad, theSidePad, theBarHeight, theColorScale, w, h) {
var bigRects = svg.append("g")
.selectAll("rect")
.data(theArray)
.enter()
.append("rect")
.attr("x", 0)
.attr("y", function(d, i) {
return i * theGap + theTopPad - 2;
})
.attr("width", function(d) {
return w - theSidePad / 2;
})
.attr("height", theGap)
.attr("stroke", "none")
.attr("fill", function(d) {
for (var i = 0; i < categories.length; i++) {
if (d.type == categories[i]) {
return d3.rgb(theColorScale(i));
}
}
})
.attr("opacity", 0.2);
var rectangles = svg.append('g')
.selectAll("rect")
.data(theArray)
.enter();
var innerRects = rectangles.append("rect")
.attr("rx", 3)
.attr("ry", 3)
.attr("x", function(d) {
// return timeScale(dateFormat(d.startTime)) + theSidePad;
return timeScale(dateFormat(d.endTime)) + theSidePad;
})
.attr("y", function(d, i) {
return i * theGap + theTopPad;
})
.attr("width", function(d) {
//return (timeScale(dateFormat(d.endTime))-timeScale(dateFormat(d.startTime)));
return (timeScale(dateFormat(d.startTime)) - timeScale(dateFormat(d.endTime)));
})
.attr("height", theBarHeight)
.attr("stroke", "none")
.attr("fill", function(d) {
for (var i = 0; i < categories.length; i++) {
if (d.type == categories[i]) {
return d3.rgb(theColorScale(i));
}
}
})
var rectText = rectangles.append("text")
.text(function(d) {
return d.task;
})
.attr("x", function(d) {
return (timeScale(dateFormat(d.endTime)) - timeScale(dateFormat(d.startTime))) / 2 + timeScale(dateFormat(d.startTime)) + theSidePad;
})
.attr("y", function(d, i) {
return i * theGap + 14 + theTopPad;
})
.attr("font-size", 11)
.attr("text-anchor", "middle")
.attr("text-height", theBarHeight)
.attr("fill", "#000000");
rectText.on('mouseover', function(e) {
// console.log(this.x.animVal.getItem(this));
var tag = "";
if (d3.select(this).data()[0].details != undefined) {
tag = "Task: " + d3.select(this).data()[0].task + "<br/>" +
"Type: " + d3.select(this).data()[0].type + "<br/>" +
"Starts: " + d3.select(this).data()[0].startTime + "<br/>" +
"Ends: " + d3.select(this).data()[0].endTime + "<br/>" +
"Details: " + d3.select(this).data()[0].details;
} else {
tag = "Task: " + d3.select(this).data()[0].task + "<br/>" +
"Type: " + d3.select(this).data()[0].type + "<br/>" +
"Starts: " + d3.select(this).data()[0].startTime + "<br/>" +
"Ends: " + d3.select(this).data()[0].endTime;
}
var output = document.getElementById("tag");
var x = this.x.animVal.getItem(this) + "px";
var y = this.y.animVal.getItem(this) + 25 + "px";
output.innerHTML = tag;
output.style.top = y;
output.style.left = x;
output.style.display = "block";
}).on('mouseout', function() {
var output = document.getElementById("tag");
output.style.display = "none";
});
innerRects.on('mouseover', function(e) {
//console.log(this);
var tag = "";
if (d3.select(this).data()[0].details != undefined) {
tag = "Task: " + d3.select(this).data()[0].task + "<br/>" +
"Type: " + d3.select(this).data()[0].type + "<br/>" +
"Starts: " + d3.select(this).data()[0].startTime + "<br/>" +
"Ends: " + d3.select(this).data()[0].endTime + "<br/>" +
"Details: " + d3.select(this).data()[0].details;
} else {
tag = "Task: " + d3.select(this).data()[0].task + "<br/>" +
"Type: " + d3.select(this).data()[0].type + "<br/>" +
"Starts: " + d3.select(this).data()[0].startTime + "<br/>" +
"Ends: " + d3.select(this).data()[0].endTime;
}
var output = document.getElementById("tag");
var x = (this.x.animVal.value + this.width.animVal.value / 2) + "px";
var y = this.y.animVal.value + 25 + "px";
output.innerHTML = tag;
output.style.top = y;
output.style.left = x;
output.style.display = "block";
}).on('mouseout', function() {
var output = document.getElementById("tag");
output.style.display = "none";
});
}
function makeGrid(theSidePad, theTopPad, w, h) {
var xAxis = d3.axisBottom(timeScale)
.ticks(d3.timeDay, 1)
.tickSize(-h + theTopPad + 20, 0, 0)
// .tickFormat(d3.timeFormat('%d %b'));
.tickFormat(d3.timeFormat('%d/%m'));
var grid = svg.append('g')
.attr('class', 'grid')
// .attr('transform', 'translate(' +theSidePad + ', ' + (h - 50) + ')')
.attr('transform', 'translate(' + theSidePad + ', ' + (h - 20) + ')')
.call(xAxis)
.selectAll("text")
.style("text-anchor", "middle")
.attr("fill", "#000000")
.attr("stroke", "none")
.attr("font-size", 10)
// .attr("dy", "1em")
.attr("dy", "0.35em")
.attr("transform", "rotate(-65)");
}
function vertLabels(theGap, theTopPad, theSidePad, theBarHeight, theColorScale) {
var numOccurances = new Array();
var prevGap = 0;
for (var i = 0; i < categories.length; i++) {
numOccurances[i] = [categories[i], getCount(categories[i], catsUnfiltered)];
}
var axisText = svg.append("g") //without doing this, impossible to put grid lines behind text
.selectAll("text")
.data(numOccurances)
.enter()
.append("text")
.text(function(d) {
return d[0];
})
.attr("x", 10)
.attr("y", function(d, i) {
if (i > 0) {
for (var j = 0; j < i; j++) {
prevGap += numOccurances[i - 1][1];
// console.log(prevGap);
return d[1] * theGap / 2 + prevGap * theGap + theTopPad;
}
} else {
return d[1] * theGap / 2 + theTopPad;
}
})
.attr("font-size", 11)
.attr("text-anchor", "start")
.attr("text-height", 14)
.attr("fill", function(d) {
for (var i = 0; i < categories.length; i++) {
if (d[0] == categories[i]) {
// console.log("true!");
return d3.rgb(theColorScale(i)).darker();
}
}
});
}
//from this stackexchange question: http://stackoverflow.com/questions/1890203/unique-for-arrays-in-javascript
function checkUnique(arr) {
var hash = {},
result = [];
for (var i = 0, l = arr.length; i < l; ++i) {
if (!hash.hasOwnProperty(arr[i])) { //it works with objects! in FF, at least
hash[arr[i]] = true;
result.push(arr[i]);
}
}
return result;
}
//from this stackexchange question: http://stackoverflow.com/questions/14227981/count-how-many-strings-in-an-array-have-duplicates-in-the-same-array
function getCounts(arr) {
var i = arr.length, // var to loop over
obj = {}; // obj to store results
while (i) obj[arr[--i]] = (obj[arr[i]] || 0) + 1; // count occurrences
return obj;
}
// get specific from everything
function getCount(word, arr) {
return getCounts(arr)[word] || 0;
}
$('#amsModal').modal({
backdrop: 'static'
});
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!DOCTYPE html>
<html>
<style>
* {
margin: 0;
padding: 0;
}
#container {
margin: 0 auto;
position: relative;
/*width: 1000px;*/
overflow: visible;
}
#chart {
/* width: 800px;
height: 400px;*/
overflow: scroll;
/*position: absolute;*/
}
.grid .tick {
stroke: lightgrey;
opacity: 0.3;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
#tag {
color: white;
background: #FA283D;
width: 150px;
position: absolute;
display: none;
padding: 3px 6px;
margin-left: -80px;
font-size: 11px;
}
#tag:before {
border: solid transparent;
content: ' ';
height: 0;
left: 50%;
margin-left: -5px;
position: absolute;
width: 0;
border-width: 10px;
border-bottom-color: #FA283D;
top: -20px;
}
.container-fluid {
margin-left: 10%;
margin-right: 10%;
}
.button {
max-width: 200px;
}
.modal-body-detail {
max-height: calc(100vh - 200px);
overflow-y: auto;
}
</style>
<head>
<title>Meh</title>
</head>
<body>
<div class='container-fluid'>
<div class="row">
<button id="btn1" type="button" class="btn btn-primary">
Long
</button>
<button id="btn2" type="button" class="btn btn-primary">
Short
</button>
</div>
<div class="modal fade autoModal " id="amsModal" tabindex="-1" role="dialog" aria-labelledby="amsModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="amsModalLabel">Orders</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div id="detailBody" class="modal-body ">
<div id="container">
<div id="chart"></div>
<!-- chart -->
<div id="tag"></div>
<!-- tooltip on hover -->
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary modal-button" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>