Browse Source

Enabled horizontal chart

pull/1/head
Masayuki Tanaka 12 years ago committed by masayuki
parent
commit
bdbb8032e3
  1. 174
      c3.js

174
c3.js

@ -74,7 +74,8 @@
__axis_y2_min = getConfig(['axis','y2','min'], null), __axis_y2_min = getConfig(['axis','y2','min'], null),
__axis_y2_center = getConfig(['axis','y2','center'], null), __axis_y2_center = getConfig(['axis','y2','center'], null),
__axis_y2_text = getConfig(['axis','y2','text'], null), __axis_y2_text = getConfig(['axis','y2','text'], null),
__axis_y2_rescale = getConfig(['axis','y2','rescale'], true) __axis_y2_rescale = getConfig(['axis','y2','rescale'], true),
__axis_rotated = getConfig(['axis','rotated'], false)
// grid // grid
var __grid_x_show = getConfig(['grid','x','show'], false), var __grid_x_show = getConfig(['grid','x','show'], false),
@ -142,10 +143,11 @@
/*-- Set Chart Params --*/ /*-- Set Chart Params --*/
var bottom = 20 + __subchart_size_height + legendHeight, var bottom = 20 + __subchart_size_height + legendHeight,
right = __axis_y2_show && !__axis_rotated ? 50 : 1,
top2 = __size_height - __subchart_size_height - legendHeight, top2 = __size_height - __subchart_size_height - legendHeight,
bottom2 = 20 + legendHeight, bottom2 = 20 + legendHeight,
top3 = __size_height - legendHeight, top3 = __size_height - legendHeight,
margin = {top: 10, right: (__axis_y2_show ? 50 : -1), bottom: bottom, left: 40}, margin = {top: 10, right: right, bottom: bottom, left: 40},
margin2 = {top: top2, right: 20, bottom: bottom2, left: 40}, margin2 = {top: top2, right: 20, bottom: bottom2, left: 40},
margin3 = {top: top3, right: 20, bottom: 0, left: 40}, margin3 = {top: top3, right: 20, bottom: 0, left: 40},
width = __size_width - margin.left - margin.right, width = __size_width - margin.left - margin.right,
@ -155,9 +157,14 @@
var parseDate = d3.time.format(__data_x_format).parse var parseDate = d3.time.format(__data_x_format).parse
var x = ((isTimeSeries) ? d3.time.scale() : d3.scale.linear()).range([0, width]), var xMin = __axis_rotated ? 10 : 0,
y = d3.scale.linear().range([height, 10]), xMax = __axis_rotated ? height : width,
y2 = d3.scale.linear().range([height, 10]), yMin = __axis_rotated ? 0 : height,
yMax = __axis_rotated ? width : 10
var x = ((isTimeSeries) ? d3.time.scale() : d3.scale.linear()).range([xMin, xMax]),
y = d3.scale.linear().range([yMin, yMax]),
y2 = d3.scale.linear().range([yMin, yMax]),
subX = ((isTimeSeries) ? d3.time.scale() : d3.scale.linear()).range([0, width]), subX = ((isTimeSeries) ? d3.time.scale() : d3.scale.linear()).range([0, width]),
subY = d3.scale.linear().range([height2, 10]), subY = d3.scale.linear().range([height2, 10]),
subY2 = d3.scale.linear().range([height2, 10]) subY2 = d3.scale.linear().range([height2, 10])
@ -168,9 +175,9 @@
yAxis2 = d3.svg.axis(), yAxis2 = d3.svg.axis(),
subXAxis = isCategorized ? categoryAxis() : d3.svg.axis() subXAxis = isCategorized ? categoryAxis() : d3.svg.axis()
xAxis.scale(x).orient("bottom") xAxis.scale(x).orient(__axis_rotated ? "left" : "bottom")
yAxis.scale(y).orient("left") yAxis.scale(y).orient(__axis_rotated ? "bottom" : "left")
yAxis2.scale(y2).orient("right") yAxis2.scale(y2).orient(__axis_rotated ? "top" : "right")
subXAxis.scale(subX).orient("bottom") subXAxis.scale(subX).orient("bottom")
if (isTimeSeries) { if (isTimeSeries) {
@ -215,9 +222,16 @@
})() })()
} }
// For main region // For main region // TODO: use nornal line when no region
var lineOnMain = function (d) { var lineOnMain = function (d) {
return isLineType(d) ? lineWithRegions(d.values, x, getYScale(d.id), __data_regions[d.id]) : "M " + x(d.values[0].x)+ " " + getYScale(d.id)(d.values[0].value) var x0, y0
if (isLineType(d)) {
return lineWithRegions(d.values, x, getYScale(d.id), __data_regions[d.id])
} else {
x0 = x(d.values[0].x)
y0 = getYScale(d.id)(d.values[0].value)
return __axis_rotated ? "M "+y0+" "+x0 : "M "+x0+" "+y0
}
} }
// For brush region // For brush region
@ -254,8 +268,9 @@
svg.select("defs").append("clipPath") svg.select("defs").append("clipPath")
.attr("id", clipId) .attr("id", clipId)
.append("rect") .append("rect")
.attr("y", 10)
.attr("width", width) .attr("width", width)
.attr("height", height) .attr("height", height-10)
svg.select("defs").append("clipPath") svg.select("defs").append("clipPath")
.attr("id", "xaxis-clip") .attr("id", "xaxis-clip")
@ -265,6 +280,14 @@
.attr("width", width + 2) .attr("width", width + 2)
.attr("height", 40) .attr("height", 40)
svg.select("defs").append("clipPath")
.attr("id", "yaxis-clip")
.append("rect")
.attr("x", -40 + 1)
.attr("y", 10 - 1)
.attr("width", 40)
.attr("height", height)
// Define regions // Define regions
var main = svg.append("g") var main = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")") .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
@ -461,6 +484,15 @@
function classCircle (d,i) { return classShape(d,i) + " __circle __circle-" + i } function classCircle (d,i) { return classShape(d,i) + " __circle __circle-" + i }
function classBar (d,i) { return classShape(d,i) + " __bar __bar-" + i } function classBar (d,i) { return classShape(d,i) + " __bar __bar-" + i }
//-- Circle --/
function circleX (d) {
return x(d.x)
}
function circleY (d) {
return getYScale(d.id)(d.value)
}
//-- Bar --// //-- Bar --//
function getBarIndices () { function getBarIndices () {
@ -481,33 +513,34 @@
return indices return indices
} }
function getBarX (barW, barTargetsNum, barIndices, isSub) { function getBarX (barW, barTargetsNum, barIndices, isSub) {
var scale = isSub ? subX : x
return function (d) { return function (d) {
var scale = isSub ? subX : x
var barIndex = d.id in barIndices ? barIndices[d.id] : 0 var barIndex = d.id in barIndices ? barIndices[d.id] : 0
return scale(d.x) - barW * (barTargetsNum/2 - barIndex) return scale(d.x) - barW * (barTargetsNum/2 - barIndex)
} }
} }
function getBarY (barH, indices, isSub) { function getBarY (barH, barIndices, zeroBased, isSub) {
var indicesIds = Object.keys(barIndices)
return function (d,i) { return function (d,i) {
var indicesIds = Object.keys(indices), offset = 0 var offset = 0
var scale = isSub ? getSubYScale(d.id) : getYScale(d.id) var scale = isSub ? getSubYScale(d.id) : getYScale(d.id)
getTargets(isBarType).forEach(function(t){ getTargets(isBarType).forEach(function(t){
if (t.id === d.id || indices[t.id] !== indices[d.id]) return if (t.id === d.id || barIndices[t.id] !== barIndices[d.id]) return
if (indicesIds.indexOf(t.id) < indicesIds.indexOf(d.id)) { if (indicesIds.indexOf(t.id) < indicesIds.indexOf(d.id)) {
offset += barH(t.values[i]) offset += barH(t.values[i])
} }
}) })
return scale(d.value) - offset return zeroBased ? offset : scale(d.value) - offset
} }
} }
function getBarW (axis, barTargetsNum) { function getBarW (axis, barTargetsNum) {
return (axis.tickOffset()*2*0.6) / barTargetsNum return (axis.tickOffset()*2*0.6) / barTargetsNum
} }
function getBarH (height, isSub) { function getBarH (height, isSub) {
var h = height === null ? function(v){ return v } : function(v){ return height-v }
return function (d) { return function (d) {
var scale = isSub ? getSubYScale(d.id) : getYScale(d.id) var scale = isSub ? getSubYScale(d.id) : getYScale(d.id)
var h = height-scale(d.value) return h(scale(d.value))
return h < 0 ? 0 : h
} }
} }
@ -598,8 +631,8 @@
.data([d]) .data([d])
.enter().append('circle') .enter().append('circle')
.attr("class", function(d){ return "selected-circle selected-circle-" + i }) .attr("class", function(d){ return "selected-circle selected-circle-" + i })
.attr("cx", function(d){ return x(d.x) }) .attr("cx", __axis_rotated ? circleY : circleX)
.attr("cy", function(d){ return getYScale(d.id)(d.value) }) .attr("cy", __axis_rotated ? circleX : circleY)
.attr("stroke", function(){ return color(d.id) }) .attr("stroke", function(){ return color(d.id) })
.attr("r", __point_select_r * 1.4) .attr("r", __point_select_r * 1.4)
.transition().duration(100) .transition().duration(100)
@ -630,6 +663,7 @@
var prev = -1, i, j var prev = -1, i, j
var s = "M" var s = "M"
var xp, yp, dx, dy, dd, diff, diff2 var xp, yp, dx, dy, dd, diff, diff2
var xValue, yValue
// Check start/end of regions // Check start/end of regions
if (typeof regions !== 'undefined') { if (typeof regions !== 'undefined') {
@ -643,13 +677,17 @@
} }
} }
// Set scales
xValue = __axis_rotated ? function(d){ return y(d.value) } : function(d){ return x(d.x) }
yValue = __axis_rotated ? function(d){ return x(d.x) } : function(d){ return y(d.value) }
// Generate // Generate
for (i = 0; i < d.length; i++) { for (i = 0; i < d.length; i++) {
// Draw as normal // Draw as normal
if (typeof regions === 'undefined' || ! isWithinRegions(d[i].x, regions)) { if (typeof regions === 'undefined' || ! isWithinRegions(d[i].x, regions)) {
s += " "+x(d[i].x)+" "+y(d[i].value) s += " "+xValue(d[i])+" "+yValue(d[i])
} }
// Draw with region // Draw with region // TODO: Fix for horizotal charts
else { else {
xp = d3.scale.linear().range([d[i-1].x, d[i].x]) xp = d3.scale.linear().range([d[i-1].x, d[i].x])
yp = d3.scale.linear().range([d[i-1].value, d[i].value]) yp = d3.scale.linear().range([d[i-1].value, d[i].value])
@ -679,7 +717,7 @@
function init (data) { function init (data) {
var targets = c3.data.targets = convertDataToTargets(data) var targets = c3.data.targets = convertDataToTargets(data)
var rectWidth var rectX, rectW
var grid, xgridLine var grid, xgridLine
// TODO: set names if names not specified // TODO: set names if names not specified
@ -770,7 +808,8 @@
.attr('class', 'chart') .attr('class', 'chart')
// Cover whole with rects for events // Cover whole with rects for events
rectWidth = ((width*getXDomainRatio())/(maxDataCount()-1)) rectW = (((__axis_rotated ? height : width)*getXDomainRatio())/(maxDataCount()-1))
rectX = function(d){ return x(d.x)-(rectW/2) }
main.select('.chart').append("g") main.select('.chart').append("g")
.attr("class", "event-rects") .attr("class", "event-rects")
.style('fill-opacity', 0) .style('fill-opacity', 0)
@ -779,10 +818,10 @@
.enter().append("rect") .enter().append("rect")
.attr("class", function(d,i){ return "event-rect event-rect-"+i }) .attr("class", function(d,i){ return "event-rect event-rect-"+i })
.style("cursor", function(d){ return __data_selection_enabled && __data_selection_grouped ? "pointer" : null }) .style("cursor", function(d){ return __data_selection_enabled && __data_selection_grouped ? "pointer" : null })
.attr("x", function(d){ return x(d.x) - (rectWidth/2) }) .attr("x", __axis_rotated ? 0 : rectX)
.attr("y", function(d){ return 0 }) .attr("y", __axis_rotated ? rectX : 0)
.attr("width", rectWidth) .attr("width", __axis_rotated ? width : rectW)
.attr("height", height) .attr("height", __axis_rotated ? rectW : height)
.on('mouseover', function(d,i) { .on('mouseover', function(d,i) {
if (dragging) return // do nothing if dragging if (dragging) return // do nothing if dragging
@ -828,7 +867,7 @@
// Set tooltip // Set tooltip
tooltip.style("top", (d3.mouse(this)[1] + 30) + "px") tooltip.style("top", (d3.mouse(this)[1] + 30) + "px")
.style("left", (x(selectedData[0].x) + 60) + "px") .style("left", ((__axis_rotated ? d3.mouse(this)[0] : x(selectedData[0].x)) + 60) + "px")
tooltip.html(__tooltip_contents(selectedData)) tooltip.html(__tooltip_contents(selectedData))
tooltip.style("visibility", "visible") tooltip.style("visibility", "visible")
}) })
@ -974,12 +1013,13 @@
// Add Axis // Add Axis
main.append("g") main.append("g")
.attr("class", "x axis") .attr("class", "x axis")
.attr("clip-path", "url(#xaxis-clip)") .attr("clip-path", __axis_rotated ? "" : "url(#xaxis-clip)")
.attr("transform", "translate(0," + height + ")") .attr("transform", "translate(0," + height + ")")
.call(xAxis) .call(__axis_rotated ? yAxis : xAxis)
main.append("g") main.append("g")
.attr("class", "y axis") .attr("class", "y axis")
.call(yAxis) .attr("clip-path", __axis_rotated ? "url(#yaxis-clip)" : "")
.call(__axis_rotated ? xAxis : yAxis)
.append("text") .append("text")
.attr("transform", "rotate(-90)") .attr("transform", "rotate(-90)")
.attr("dy", "1.4em") .attr("dy", "1.4em")
@ -987,10 +1027,12 @@
.style("text-anchor", "end") .style("text-anchor", "end")
.text(__axis_y_text) .text(__axis_y_text)
main.append("g") if (__axis_y2_show) {
.attr("class", "y2 axis") main.append("g")
.attr("transform", "translate(" + width + ",0)") .attr("class", "y2 axis")
.call(yAxis2) .attr("transform", "translate(" + (__axis_rotated ? 0 : width) + "," + (__axis_rotated ? 10 : 0) + ")")
.call(yAxis2)
}
/*-- Context Region --*/ /*-- Context Region --*/
@ -1045,26 +1087,26 @@
var mainPath, mainCircle, mainBar, contextPath var mainPath, mainCircle, mainBar, contextPath
var barIndices = getBarIndices(), barTargetsNum = barIndices.__max__ + 1 var barIndices = getBarIndices(), barTargetsNum = barIndices.__max__ + 1
var barX, barY, barW, barH var barX, barY, barW, barH
var rectWidth var rectX, rectW
withY = (typeof withY === 'undefined') ? false : withY withY = (typeof withY === 'undefined') ? false : withY
withSubchart = (typeof withSubchart === 'undefined') ? false : withSubchart withSubchart = (typeof withSubchart === 'undefined') ? false : withSubchart
// ticks for x-axis
// ATTENTION: call here to update tickOffset
x.domain(brush.empty() ? subX.domain() : brush.extent())
main.selectAll(".x.axis").call(__axis_rotated ? yAxis : xAxis)
// Update main domains // Update main domains
y.domain(getYDomain(c3.data.targets, 'y')) y.domain(getYDomain(c3.data.targets, 'y'))
y2.domain(getYDomain(c3.data.targets, 'y2')) y2.domain(getYDomain(c3.data.targets, 'y2'))
main.selectAll(".y.axis").transition().call(yAxis) main.selectAll(".y.axis").transition().duration(__axis_rotated ? 0 : 250).call(__axis_rotated ? xAxis : yAxis)
main.selectAll(".y2.axis").transition().call(yAxis2) main.selectAll(".y2.axis").transition().call(yAxis2)
// Update sub domain // Update sub domain
subY.domain(y.domain()) subY.domain(y.domain())
subY2.domain(y2.domain()) subY2.domain(y2.domain())
// ticks for x-axis
// ATTENTION: call here to update tickOffset
x.domain(brush.empty() ? subX.domain() : brush.extent())
main.selectAll(".x.axis").call(xAxis)
// grid // grid
if (__grid_x_show) { if (__grid_x_show) {
if (__grid_x_type === 'year') { if (__grid_x_type === 'year') {
@ -1119,16 +1161,22 @@
// bars // bars
barW = getBarW(xAxis, barTargetsNum) barW = getBarW(xAxis, barTargetsNum)
barH = getBarH(height) barH = getBarH(__axis_rotated ? null : height)
barX = getBarX(barW, barTargetsNum, barIndices) barX = getBarX(barW, barTargetsNum, barIndices)
barY = getBarY(barH, barIndices) barY = getBarY(barH, barIndices, __axis_rotated)
mainBar = main.selectAll('.__bars').selectAll('.__bar') mainBar = main.selectAll('.__bars').selectAll('.__bar')
.data(barData) .data(barData)
mainBar.transition().duration(withTransition ? 250 : 0) mainBar.transition().duration(withTransition ? 250 : 0)
.attr("x", barX).attr("y", barY).attr("width", barW).attr("height", barH) .attr("x", __axis_rotated ? barY : barX)
.attr("y", __axis_rotated ? barX : barY)
.attr("width", __axis_rotated ? barH : barW)
.attr("height", __axis_rotated ? barW : barH)
mainBar.enter().append('rect') mainBar.enter().append('rect')
.attr("class", classBar) .attr("class", classBar)
.attr("x", barX).attr("y", barY).attr("width", barW).attr("height", barH) .attr("x", __axis_rotated ? barY : barX)
.attr("y", __axis_rotated ? barX : barY)
.attr("width", __axis_rotated ? barH : barW)
.attr("height", __axis_rotated ? barW : barH)
.style("opacity", 0) .style("opacity", 0)
.transition().duration(withTransition ? 250 : 0) .transition().duration(withTransition ? 250 : 0)
.style('opacity', 1) .style('opacity', 1)
@ -1143,12 +1191,12 @@
mainCircle = main.selectAll('.__circles').selectAll('.__circle') mainCircle = main.selectAll('.__circles').selectAll('.__circle')
.data(lineData) .data(lineData)
mainCircle.transition().duration(withTransition ? 250 : 0) mainCircle.transition().duration(withTransition ? 250 : 0)
.attr("cx", function(d){ return x(d.x) }) .attr("cx", __axis_rotated ? circleY : circleX)
.attr("cy", function(d){ return getYScale(d.id)(d.value) }) .attr("cy", __axis_rotated ? circleX : circleY)
mainCircle.enter().append("circle") mainCircle.enter().append("circle")
.attr("class", classCircle) .attr("class", classCircle)
.attr("cx", function(d){ return x(d.x) }) .attr("cx", __axis_rotated ? circleY : circleX)
.attr("cy", function(d){ return getYScale(d.id)(d.value) }) .attr("cy", __axis_rotated ? circleX : circleY)
.attr("r", __point_r) .attr("r", __point_r)
mainCircle.exit().remove() mainCircle.exit().remove()
@ -1158,7 +1206,7 @@
barW = getBarW(subXAxis, barTargetsNum) barW = getBarW(subXAxis, barTargetsNum)
barH = getBarH(height2, true) barH = getBarH(height2, true)
barX = getBarX(barW, barTargetsNum, barIndices, true) barX = getBarX(barW, barTargetsNum, barIndices, true)
barY = getBarY(barH, barIndices, true) barY = getBarY(barH, barIndices, false, true)
contextBar = context.selectAll('.__bars').selectAll('.__bar') contextBar = context.selectAll('.__bars').selectAll('.__bar')
.data(barData) .data(barData)
contextBar.transition().duration(withTransition ? 250 : 0) contextBar.transition().duration(withTransition ? 250 : 0)
@ -1185,14 +1233,17 @@
.selectAll('circle') .selectAll('circle')
.remove() .remove()
main.selectAll('.selected-circle') main.selectAll('.selected-circle')
.attr("cx", function(d) { return x(d.x) }) .attr("cx", __axis_rotated ? circleY : circleX)
.attr("cy", function(d) { return getYScale(d.id)(d.value) }) .attr("cy", __axis_rotated ? circleX : circleY)
// rect for mouseover // rect for mouseover
rectWidth = ((width*getXDomainRatio())/(maxDataCount()-1)) rectW = (((__axis_rotated ? height : width)*getXDomainRatio())/(maxDataCount()-1))
main.selectAll('rect.event-rect') rectX = function(d){ return x(d.x)-(rectW/2) }
.attr("width", rectWidth) main.selectAll('.event-rect')
.attr("x", function(d) { return x(d.x) - (rectWidth/2) }) .attr("x", __axis_rotated ? 0 : rectX)
.attr("y", __axis_rotated ? rectX : 0)
.attr("width", __axis_rotated ? width : rectW)
.attr("height", __axis_rotated ? rectW : height)
main.selectAll('rect.region') main.selectAll('rect.region')
.attr("x", regionStart) .attr("x", regionStart)
.attr("width", regionWidth) .attr("width", regionWidth)
@ -1535,7 +1586,7 @@
} }
function axisY (selection, y) { function axisY (selection, y) {
selection.attr("transform", function(d){ selection.attr("transform", function(d){
return "translate(" + y(d) + ",0)" // TODO: Fix scale return "translate(0," + y(d) + ")"
}) })
} }
function scaleExtent (domain) { function scaleExtent (domain) {
@ -1598,17 +1649,20 @@
pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize) pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize)
break break
} }
*/
case "left": case "left":
{ {
tickTransform = axisY tickTransform = axisY
lineEnter.attr("x2", -tickMajorSize) lineEnter.attr("x2", -tickMajorSize)
textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)) textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding))
lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0) lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0)
textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0) textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", tickOffset)
text.attr("dy", ".32em").style("text-anchor", "end") text.attr("dy", ".32em").style("text-anchor", "end")
text.text(function(i){ return shouldShowTickText(ticks, i) ? category(i) : "" })
pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize) pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize)
break break
} }
/*
case "right": case "right":
{ {
tickTransform = axisY tickTransform = axisY

Loading…
Cancel
Save