Commit bc0b6db9 authored by DungSaga's avatar DungSaga

Merge pull request #1 from masayuki0812/master

Update from base repo
parents f05f765c 90387157
......@@ -29,3 +29,5 @@ Please fork this fiddle:
## License
MIT
[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=masayuki0812&url=https://github.com/masayuki0812/c3&title=c3&language=javascript&tags=github&category=software)
......@@ -4,7 +4,7 @@
"c3.css",
"c3.js"
],
"version": "0.3.0",
"version": "0.4.3",
"homepage": "https://github.com/masayuki0812/c3",
"authors": [
"Masayuki Tanaka <masayuki0812@mac.com>"
......
......@@ -209,5 +209,5 @@
.c3-chart-arc .c3-gauge-value {
fill: #000;
font-size: 28px;
/* font-size: 28px !important;*/
}
.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-chart-arcs-title{font-size:1.3em}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000;font-size:28px}
\ No newline at end of file
.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-chart-arcs-title{font-size:1.3em}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -2,7 +2,7 @@
"name": "c3",
"repo": "masayuki0812/c3",
"description": "A D3-based reusable chart library",
"version": "0.3.0",
"version": "0.4.3",
"keywords": [],
"dependencies": {
"mbostock/d3": "v3.4.4"
......
......@@ -273,6 +273,9 @@
<a href="./samples/regions.html">
Show regions
</a>
<a href="./samples/regions_timeseries.html">
Show regions with timeseries
</a>
</div>
<div class="col-md-4">
<h3>Legend</h3>
......
<html>
<head>
<link rel="stylesheet" type="text/css" href="/css/c3.css">
</head>
<body>
<div id="chart"></div>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="/js/c3.js"></script>
<script>
var chart = c3.generate({
data: {
x: 'date',
columns: [
['date', '2014-01-01', '2014-01-10', '2014-01-20', '2014-01-30', '2014-02-01'],
['sample', 30, 200, 100, 400, 150, 250]
]
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%Y%m%d %H:%M:%S'
}
},
},
regions: [
{start: '2014-01-05', end: '2014-01-10'},
// {start: new Date('2014-01-10'), end: new Date('2014-01-15')},
{start: 1390608000000, end: 1391040000000}
]
});
setTimeout(function () {
chart.load({
columns: [
['date', +new Date('2014-01-01'), +new Date('2014-01-10'), +new Date('2014-03-01')],
['sample', 100, 200, 300]
]
});
chart.regions([
{start: +new Date('2014-01-10'), end: +new Date('2014-01-15')}
]);
}, 1000);
</script>
</body>
</html>
{
"name": "c3",
"version": "0.3.0",
"version": "0.4.3",
"description": "D3-based reusable chart library",
"main": "c3.js",
"scripts": {
......
var describe = window.describe,
expect = window.expect,
it = window.it,
beforeEach = window.beforeEach;
describe('c3 api grid', function () {
'use strict';
var chart, d3;
var args = {
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250]
]
}
};
beforeEach(function (done) {
chart = window.initChart(chart, args, done);
d3 = chart.internal.d3;
});
describe('ygrid.add and ygrid.remove', function () {
it('should update y grids', function (done) {
var main = chart.internal.main,
expectedGrids = [
{
value: 100,
text: 'Pressure Low'
},
{
value: 200,
text: 'Pressure High'
}
],
grids;
// Call ygrids.add
chart.ygrids.add(expectedGrids);
setTimeout(function () {
grids = main.selectAll('.c3-ygrid-line');
expect(grids.size()).toBe(expectedGrids.length);
grids.each(function (d, i) {
var y = +d3.select(this).select('line').attr('y1'),
text = d3.select(this).select('text').text(),
expectedY = Math.round(chart.internal.y(expectedGrids[i].value)),
expectedText = expectedGrids[i].text;
expect(y).toBe(expectedY);
expect(text).toBe(expectedText);
});
// Call ygrids.remove
chart.ygrids.remove(expectedGrids);
setTimeout(function () {
grids = main.selectAll('.c3-ygrid-line');
expect(grids.size()).toBe(0);
}, 500);
}, 500);
setTimeout(function () {
done();
}, 1200);
});
it("should update x ygrids even if it's zoomed", function (done) {
var main = chart.internal.main,
expectedGrids = [
{
value: 0,
text: 'Pressure Low'
},
{
value: 1,
text: 'Pressure High'
}
],
grids, domain;
chart.zoom([0, 2]);
setTimeout(function () {
// Call xgrids
chart.xgrids(expectedGrids);
setTimeout(function () {
grids = main.selectAll('.c3-xgrid-line');
expect(grids.size()).toBe(expectedGrids.length);
grids.each(function (d, i) {
var x = +d3.select(this).select('line').attr('x1'),
text = d3.select(this).select('text').text(),
expectedX = Math.round(chart.internal.x(expectedGrids[i].value)),
expectedText = expectedGrids[i].text;
expect(x).toBe(expectedX);
expect(text).toBe(expectedText);
});
// check if it was not rescaled
domain = chart.internal.y.domain();
expect(domain[0]).toBeLessThan(0);
expect(domain[1]).toBeGreaterThan(400);
// Call xgrids.remove
chart.xgrids.remove(expectedGrids);
setTimeout(function () {
grids = main.selectAll('.c3-xgrid-line');
expect(grids.size()).toBe(0);
}, 500); // for xgrids.remove()
}, 500); // for xgrids()
}, 500); // for zoom
setTimeout(function () {
done();
}, 1700);
});
});
});
var describe = window.describe,
expect = window.expect,
it = window.it,
beforeEach = window.beforeEach;
describe('c3 chart axis', function () {
'use strict';
var chart, d3, args;
beforeEach(function (done) {
if (typeof chart === 'undefined') {
window.initDom();
}
chart = window.c3.generate(args);
d3 = chart.internal.d3;
chart.internal.d3.select('.jasmine_html-reporter')
.style('position', 'absolute')
.style('right', 0);
window.setTimeout(function () {
done();
}, 50);
});
describe('show pie chart', function () {
args = {
data: {
columns: [
['data1', 30],
['data2', 150],
['data3', 120]
],
type: 'pie'
}
};
it('should have correct classes', function () {
var chartArc = d3.select('.c3-chart-arcs'),
arcs = {
data1: chartArc.select('.c3-chart-arc.c3-target.c3-target-data1')
.select('g.c3-shapes.c3-shapes-data1.c3-arcs.c3-arcs-data1')
.select('path.c3-shape.c3-shape.c3-arc.c3-arc-data1'),
data2: chartArc.select('.c3-chart-arc.c3-target.c3-target-data2')
.select('g.c3-shapes.c3-shapes-data2.c3-arcs.c3-arcs-data2')
.select('path.c3-shape.c3-shape.c3-arc.c3-arc-data2'),
data3: chartArc.select('.c3-chart-arc.c3-target.c3-target-data3')
.select('g.c3-shapes.c3-shapes-data3.c3-arcs.c3-arcs-data3')
.select('path.c3-shape.c3-shape.c3-arc.c3-arc-data3')
};
expect(arcs.data1.size()).toBe(1);
expect(arcs.data2.size()).toBe(1);
expect(arcs.data3.size()).toBe(1);
});
it('should have correct d', function () {
expect(d3.select('.c3-arc-data1').attr('d')).toMatch(/M-124\..+,-171\..+A211\..+,211\..+ 0 0,1 -3\..+,-211\..+L0,0Z/);
expect(d3.select('.c3-arc-data2').attr('d')).toMatch(/M1\..+,-211\..+A211\..+,211\..+ 0 0,1 1\..+,211\..+L0,0Z/);
expect(d3.select('.c3-arc-data3').attr('d')).toMatch(/M1\..+,211\..+A211\..+,211\..+ 0 0,1 -124\..+,-171\..+L0,0Z/);
});
it('should set args with data id that can be converted to a color', function () {
args.data.columns = [
['black', 30],
['data2', 150],
['data3', 120]
];
expect(true).toBeTruthy();
});
it('should have correct d even if data id can be converted to a color', function () {
expect(d3.select('.c3-arc-black').attr('d')).toMatch(/M-124\..+,-171\..+A211\..+,211\..+ 0 0,1 -3\..+,-211\..+L0,0Z/);
});
});
});
......@@ -10,14 +10,34 @@ function initDom() {
}
typeof initDom !== 'undefined';
function setEvent(chart, x, y) {
function setMouseEvent(chart, name, x, y, element) {
'use strict';
var paddingLeft = chart.internal.main.node().transform.baseVal.getItem(0).matrix.e,
evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window,
event = document.createEvent("MouseEvents");
event.initMouseEvent(name, true, true, window,
0, 0, 0, x + paddingLeft, y + 5,
false, false, false, false, 0, null);
chart.internal.d3.event = evt;
chart.internal.d3.event = event;
if (element) { element.dispatchEvent(event); }
}
typeof setEvent !== 'undefined';
typeof setMouseEvent !== 'undefined';
function initChart(chart, args, done) {
'use strict';
if (typeof chart === 'undefined') {
window.initDom();
}
chart = window.c3.generate(args);
chart.internal.d3.select('.jasmine_html-reporter')
.style('position', 'absolute')
.style('right', 0);
window.setTimeout(function () {
done();
}, 10);
return chart;
}
typeof initChart !== 'undefined';
var describe = window.describe,
expect = window.expect,
it = window.it,
beforeEach = window.beforeEach;
describe('c3 chart class', function () {
'use strict';
var chart, d3;
var args = {
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2 prefix', 50, 20, 10, 40, 15, 25],
['data3 мужчины', 150, 120, 110, 140, 115, 125]
]
}
};
beforeEach(function (done) {
chart = window.initChart(chart, args, done);
d3 = chart.internal.d3;
});
describe('internal.getTargetSelectorSuffix', function () {
it('should not replace any characters', function () {
var input = 'data1',
expected = '-' + input,
suffix = chart.internal.getTargetSelectorSuffix(input);
expect(suffix).toBe(expected);
});
it('should replace space to "-"', function () {
var input = 'data1 suffix',
expected = '-data1-suffix',
suffix = chart.internal.getTargetSelectorSuffix(input);
expect(suffix).toBe(expected);
});
it('should replace space to "-" with multibyte characters', function () {
var input = 'data1 suffix 日本語',
expected = '-data1-suffix-日本語',
suffix = chart.internal.getTargetSelectorSuffix(input);
expect(suffix).toBe(expected);
});
it('should replace special charactors to "-"', function () {
var input = 'data1 !@#$%^&*()_=+,.<>"\':;[]/|?~`{}\\',
expected = '-data1--------------------------------',
suffix = chart.internal.getTargetSelectorSuffix(input);
expect(suffix).toBe(expected);
});
});
describe('multibyte characters on chart', function () {
it('should replace space to "-" with multibyte characters', function () {
var selector = '.c3-target-data3-мужчины';
expect(chart.internal.main.select(selector).size()).toBe(1);
});
});
});
......@@ -8,35 +8,66 @@ describe('c3 chart', function () {
var chart, d3;
beforeEach(function () {
window.initDom();
chart = window.c3.generate({
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25],
['data3', 150, 120, 110, 140, 115, 125]
]
}
});
var args = {
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25],
['data3', 150, 120, 110, 140, 115, 125]
]
}
};
beforeEach(function (done) {
chart = window.initChart(chart, args, done);
d3 = chart.internal.d3;
});
it('should be created', function () {
var svg = d3.select('#chart svg');
expect(svg).not.toBeNull();
describe('init', function () {
it('should be created', function () {
var svg = d3.select('#chart svg');
expect(svg).not.toBeNull();
});
it('should set 3rd party property to Function', function () {
Function.prototype.$extIsFunction = true;
expect(true).toBeTruthy();
});
it('should be created even if 3rd party property has been set', function () {
var svg = d3.select('#chart svg');
expect(svg).not.toBeNull();
});
});
it('should have same width', function () {
var svg = d3.select('#chart svg');
expect(+svg.attr('width')).toBe(640);
describe('size', function () {
it('should have same width', function () {
var svg = d3.select('#chart svg');
expect(+svg.attr('width')).toBe(640);
});
it('should have same height', function () {
var svg = d3.select('#chart svg');
expect(+svg.attr('height')).toBe(480);
});
});
it('should have same height', function () {
var svg = d3.select('#chart svg');
expect(+svg.attr('height')).toBe(480);
describe('bindto', function () {
it('should accept d3.selection object', function () {
args.bindto = d3.select('#chart');
expect(true).toBeTruthy();
});
it('should be created', function () {
var svg = d3.select('#chart svg');
expect(svg).not.toBeNull();
});
});
});
......@@ -114,7 +114,8 @@ describe('c3 chart data', function () {
x: {
type: 'timeseries',
tick: {
format: '%Y-%m-%d %H:%M:%S.%L'
format: '%Y-%m-%d %H:%M:%S.%L',
multiline: false
}
}
}
......
var describe = window.describe,
expect = window.expect,
it = window.it,
beforeEach = window.beforeEach;
describe('c3 chart grid', function () {
'use strict';
var chart, d3;
var args = {
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250]
]
},
axis: {
y: {
tick: {
}
}
},
grid: {
y: {
show: false
}
}
};
beforeEach(function (done) {
chart = window.initChart(chart, args, done);
d3 = chart.internal.d3;
});
describe('y grid', function () {
it('should not show y grids', function () {
expect(chart.internal.main.select('.c3-ygrids').size()).toBe(0);
});
it('should update args to show y grids', function () {
args.grid.y.show = true;
expect(true).toBeTruthy();
});
it('should show y grids', function () {
var ygrids = chart.internal.main.select('.c3-ygrids');
expect(ygrids.size()).toBe(1);
expect(ygrids.selectAll('.c3-ygrid').size()).toBe(9);
});
it('should update args to show only 3 y grids', function () {
args.grid.y.ticks = 3;
expect(true).toBeTruthy();
});
it('should show only 3 y grids', function () {
var ygrids = chart.internal.main.select('.c3-ygrids');
expect(ygrids.size()).toBe(1);
expect(ygrids.selectAll('.c3-ygrid').size()).toBe(3);
});
it('should update args to show y grids depending on y axis ticks', function () {
args.axis.y.tick.count = 5;
expect(true).toBeTruthy();
});
it('should show grids depending on y axis ticks', function () {
var ygrids = chart.internal.main.select('.c3-ygrids'),
expectedYs = [];
ygrids.selectAll('.c3-ygrid').each(function (d, i) {
expectedYs[i] = +d3.select(this).attr('y1');
});
expect(ygrids.size()).toBe(1);
expect(ygrids.selectAll('.c3-ygrid').size()).toBe(5);
chart.internal.main.select('.c3-axis-y').selectAll('.tick').each(function (d, i) {
var t = d3.transform(d3.select(this).attr('transform'));
expect(t.translate[1]).toBe(expectedYs[i]);
});
});
});
});
......@@ -84,6 +84,26 @@ describe('c3 chart legend', function () {
expect(box.height).toBe(48);
});
it('should update args to have only one series', function () {
args = {
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
]
},
legend: {
position: 'inset'
}
};
expect(true).toBeTruthy();
});
it('should locate legend properly', function () {
var box = d3.select('.c3-legend-background').node().getBoundingClientRect();
expect(box.height).toBe(28);
expect(box.width).toBeGreaterThan(64);
});
});
});
......@@ -3,8 +3,7 @@ var describe = window.describe,
it = window.it,
beforeEach = window.beforeEach;
var initDom = window.initDom,
setEvent = window.setEvent;
var setMouseEvent = window.setMouseEvent;
describe('c3 chart shape bar', function () {
'use strict';
......@@ -26,16 +25,8 @@ describe('c3 chart shape bar', function () {
};
beforeEach(function (done) {
if (typeof chart === 'undefined') {
initDom();
}
chart = window.c3.generate(args);
chart = window.initChart(chart, args, done);
d3 = chart.internal.d3;
chart.internal.d3.select('.jasmine_html-reporter').style('display', 'none');
window.setTimeout(function () {
done();
}, 10);
});
describe('internal.isWithinBar', function () {
......@@ -44,25 +35,25 @@ describe('c3 chart shape bar', function () {
it('should not be within bar', function () {
var bar = d3.select('.c3-target-data1 .c3-bar-0').node();
setEvent(chart, 0, 0);
setMouseEvent(chart, 'click', 0, 0);
expect(chart.internal.isWithinBar(bar)).toBeFalsy();
});
it('should be within bar', function () {
var bar = d3.select('.c3-target-data1 .c3-bar-0').node();
setEvent(chart, 31, 280);
setMouseEvent(chart, 'click', 31, 280);
expect(chart.internal.isWithinBar(bar)).toBeTruthy();
});
it('should not be within bar of negative value', function () {
var bar = d3.select('.c3-target-data3 .c3-bar-0').node();
setEvent(chart, 68, 280);
setMouseEvent(chart, 'click', 68, 280);
expect(chart.internal.isWithinBar(bar)).toBeFalsy();
});
it('should be within bar of negative value', function () {
var bar = d3.select('.c3-target-data3 .c3-bar-0').node();
setEvent(chart, 68, 350);
setMouseEvent(chart, 'click', 68, 350);
expect(chart.internal.isWithinBar(bar)).toBeTruthy();
});
......@@ -77,19 +68,19 @@ describe('c3 chart shape bar', function () {
it('should not be within bar', function () {
var bar = d3.select('.c3-target-data1 .c3-bar-0').node();
setEvent(chart, 0, 0);
setMouseEvent(chart, 'click', 0, 0);
expect(chart.internal.isWithinBar(bar)).toBeFalsy();
});
it('should be within bar', function () {
var bar = d3.select('.c3-target-data1 .c3-bar-0').node();
setEvent(chart, 190, 20);
setMouseEvent(chart, 'click', 190, 20);
expect(chart.internal.isWithinBar(bar)).toBeTruthy();
});
it('should be within bar of negative value', function () {
var bar = d3.select('.c3-target-data3 .c3-bar-0').node();
setEvent(chart, 68, 50);
setMouseEvent(chart, 'click', 68, 50);
expect(chart.internal.isWithinBar(bar)).toBeTruthy();
});
......
var describe = window.describe,
expect = window.expect,
it = window.it,
beforeEach = window.beforeEach;
describe('c3 chart tooltip', function () {
'use strict';
var chart, d3;
var args = {
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25],
['data3', 150, 120, 110, 140, 115, 125]
]
}
};
beforeEach(function (done) {
chart = window.initChart(chart, args, done);
d3 = chart.internal.d3;
});
describe('tooltip position', function () {
describe('without left margin', function () {
it('should show tooltip on proper position', function () {
var eventRect = d3.select('.c3-event-rect-2').node();
window.setMouseEvent(chart, 'mousemove', 100, 100, eventRect);
var tooltipContainer = d3.select('.c3-tooltip-container'),
top = Math.floor(+tooltipContainer.style('top').replace(/px/, '')),
left = Math.floor(+tooltipContainer.style('left').replace(/px/, '')),
topExpected = 115,
leftExpected = 304;
expect(top).toBe(topExpected);
expect(left).toBe(leftExpected);
});
});
describe('with left margin', function () {
it('should set left margin', function () {
d3.select('#chart').style('margin-left', '300px');
expect(true).toBeTruthy();
});
it('should show tooltip on proper position', function () {
var eventRect = d3.select('.c3-event-rect-2').node();
window.setMouseEvent(chart, 'mousemove', 100, 100, eventRect);
var tooltipContainer = d3.select('.c3-tooltip-container'),
top = Math.floor(+tooltipContainer.style('top').replace(/px/, '')),
left = Math.floor(+tooltipContainer.style('left').replace(/px/, '')),
topExpected = 115,
leftExpected = 304;
expect(top).toBe(topExpected);
expect(left).toBe(leftExpected);
});
});
});
});
var describe = window.describe,
expect = window.expect,
it = window.it,
beforeEach = window.beforeEach;
describe('c3 chart zoom', function () {
'use strict';
var chart, d3;
var args = {
data: {
columns: [
['data1', 30, 200, 100, 400, 3150, 250],
['data2', 50, 20, 10, 40, 15, 6025]
]
},
axis: {
x: {
extent: [1, 2]
}
},
zoom: {
enable: true
},
subchart: {
show: true
}
};
beforeEach(function (done) {
chart = window.initChart(chart, args, done);
d3 = chart.internal.d3;
});
describe('default extent', function () {
describe('main chart domain', function () {
it('should have original y domain', function () {
var yDomain = chart.internal.y.domain(),
expectedYDomain = [-591.5, 6626.5];
expect(yDomain[0]).toBe(expectedYDomain[0]);
expect(yDomain[1]).toBe(expectedYDomain[1]);
});
});
describe('main chart domain', function () {
it('should have original y domain in subchart', function () {
var yDomain = chart.internal.y.domain(),
subYDomain = chart.internal.subY.domain();
expect(subYDomain[0]).toBe(yDomain[0]);
expect(subYDomain[1]).toBe(yDomain[1]);
});
});
describe('main chart domain', function () {
it('should have specified brush extent', function () {
var brushExtent = chart.internal.brush.extent(),
expectedBrushExtent = [1, 2];
expect(brushExtent[0]).toBe(expectedBrushExtent[0]);
expect(brushExtent[1]).toBe(expectedBrushExtent[1]);
});
});
});
});
......@@ -15,5 +15,6 @@ c3_chart_fn.destroy = function () {
$$.data.targets = undefined;
$$.data.xs = {};
$$.selectChart.classed('c3', false).html("");
window.clearInterval($$.intervalForObserveInserted);
window.onresize = null;
};
......@@ -2,7 +2,7 @@ c3_chart_fn.xgrids = function (grids) {
var $$ = this.internal, config = $$.config;
if (! grids) { return config.grid_x_lines; }
config.grid_x_lines = grids;
$$.redraw();
$$.redrawWithoutRescale();
return config.grid_x_lines;
};
c3_chart_fn.xgrids.add = function (grids) {
......@@ -18,7 +18,7 @@ c3_chart_fn.ygrids = function (grids) {
var $$ = this.internal, config = $$.config;
if (! grids) { return config.grid_y_lines; }
config.grid_y_lines = grids;
$$.redraw();
$$.redrawWithoutRescale();
return config.grid_y_lines;
};
c3_chart_fn.ygrids.add = function (grids) {
......
......@@ -2,14 +2,14 @@ c3_chart_fn.regions = function (regions) {
var $$ = this.internal, config = $$.config;
if (!regions) { return config.regions; }
config.regions = regions;
$$.redraw();
$$.redrawWithoutRescale();
return config.regions;
};
c3_chart_fn.regions.add = function (regions) {
var $$ = this.internal, config = $$.config;
if (!regions) { return config.regions; }
config.regions = config.regions.concat(regions);
$$.redraw();
$$.redrawWithoutRescale();
return config.regions;
};
c3_chart_fn.regions.remove = function (options) {
......
......@@ -5,7 +5,8 @@ c3_chart_fn.zoom = function (domain) {
domain = domain.map(function (x) { return $$.parseDate(x); });
}
$$.brush.extent(domain);
$$.redraw({withUpdateXDomain: true});
$$.redraw({withUpdateXDomain: true, withY: $$.config.zoom_rescale});
$$.config.zoom_onzoom.call(this, $$.x.orgDomain());
}
return $$.brush.extent();
};
......
......@@ -127,7 +127,9 @@ c3_chart_internal_fn.expandArc = function (targetIds) {
interval = window.setInterval(function () {
if (!$$.transiting) {
window.clearInterval(interval);
$$.expandArc(targetIds);
if ($$.legend.selectAll('.c3-legend-item-focused').size() > 0) {
$$.expandArc(targetIds);
}
}
}, 10);
return;
......@@ -216,7 +218,7 @@ c3_chart_internal_fn.updateTargetsForArc = function (targets) {
mainPieEnter.append('g')
.attr('class', classArcs);
mainPieEnter.append("text")
.attr("dy", $$.hasType('gauge') ? "-0.35em" : ".35em")
.attr("dy", $$.hasType('gauge') ? "-.1em" : ".35em")
.style("opacity", 0)
.style("text-anchor", "middle")
.style("pointer-events", "none");
......@@ -311,7 +313,11 @@ c3_chart_internal_fn.redrawArc = function (duration, durationForExit, withTransf
}
interpolate = d3.interpolate(this._current, updated);
this._current = interpolate(0);
return function (t) { return $$.getArc(interpolate(t), true); };
return function (t) {
var interpolated = interpolate(t);
interpolated.data = d.data; // data.id will be updated by interporator
return $$.getArc(interpolated, true);
};
})
.attr("transform", withTransform ? "scale(1)" : "")
.style("fill", function (d) {
......@@ -329,7 +335,8 @@ c3_chart_internal_fn.redrawArc = function (duration, durationForExit, withTransf
.attr('class', function (d) { return $$.isGaugeType(d.data) ? CLASS.gaugeValue : ''; })
.text($$.textForArcLabel.bind($$))
.attr("transform", $$.transformForArcLabel.bind($$))
.transition().duration(duration)
.style('font-size', function (d) { return $$.isGaugeType(d.data) ? Math.round($$.radius / 5) + 'px' : ''; })
.transition().duration(duration)
.style("opacity", function (d) { return $$.isTargetToShow(d.data.id) && $$.isArcType(d.data) ? 1 : 0; });
main.select('.' + CLASS.chartArcsTitle)
.style("opacity", $$.hasType('donut') || $$.hasType('gauge') ? 1 : 0);
......
......@@ -35,7 +35,8 @@ c3_chart_internal_fn.getXAxis = function (scale, orient, tickFormat, tickValues,
axisParams = {
isCategory: $$.isCategorized(),
withOuterTick: withOuterTick,
tickWidth: $$.isCategorized() ? config.axis_x_tick_width : undefined
tickMultiline: config.axis_x_tick_multiline,
tickWidth: config.axis_x_tick_width
},
axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient);
......@@ -63,8 +64,14 @@ c3_chart_internal_fn.getXAxis = function (scale, orient, tickFormat, tickValues,
return axis;
};
c3_chart_internal_fn.getYAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
var axisParams = {withOuterTick: withOuterTick};
return c3_axis(this.d3, axisParams).scale(scale).orient(orient).tickFormat(tickFormat).tickValues(tickValues);
var axisParams = {withOuterTick: withOuterTick},
axis = c3_axis(this.d3, axisParams).scale(scale).orient(orient).tickFormat(tickFormat);
if (this.isTimeSeriesY()) {
axis.ticks(this.d3.time[this.config.axis_y_tick_time_value], this.config.axis_y_tick_time_interval);
} else {
axis.tickValues(tickValues);
}
return axis;
};
c3_chart_internal_fn.getAxisId = function (id) {
var config = this.config;
......@@ -242,7 +249,7 @@ c3_chart_internal_fn.textAnchorForY2AxisLabel = function () {
};
c3_chart_internal_fn.xForRotatedTickText = function (r) {
return 10 * Math.sin(Math.PI * (r / 180));
return 8 * Math.sin(Math.PI * (r / 180));
};
c3_chart_internal_fn.yForRotatedTickText = function (r) {
return 11.5 - 2.5 * (r / 15) * (r > 0 ? 1 : -1);
......@@ -252,24 +259,28 @@ c3_chart_internal_fn.rotateTickText = function (axis, transition, rotate) {
.style("text-anchor", rotate > 0 ? "start" : "end");
transition.selectAll('.tick text')
.attr("y", this.yForRotatedTickText(rotate))
.attr("x", this.xForRotatedTickText(rotate))
.attr("transform", "rotate(" + rotate + ")");
.attr("transform", "rotate(" + rotate + ")")
.selectAll('tspan')
.attr('dx', this.xForRotatedTickText(rotate));
};
c3_chart_internal_fn.getMaxTickWidth = function (id) {
c3_chart_internal_fn.getMaxTickWidth = function (id, withoutRecompute) {
var $$ = this, config = $$.config,
maxWidth = 0, targetsToShow, scale, axis;
if (withoutRecompute && $$.currentMaxTickWidths[id]) {
return $$.currentMaxTickWidths[id];
}
if ($$.svg) {
targetsToShow = $$.filterTargetsToShow($$.data.targets);
if (id === 'y') {
scale = $$.y.copy().domain($$.getYDomain(targetsToShow, 'y'));
axis = $$.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.getYAxisTickValues());
axis = $$.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues);
} else if (id === 'y2') {
scale = $$.y2.copy().domain($$.getYDomain(targetsToShow, 'y2'));
axis = $$.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.getY2AxisTickValues());
axis = $$.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues);
} else {
scale = $$.x.copy().domain($$.getXDomain(targetsToShow));
axis = $$.getXAxis(scale, $$.xOrient, $$.getXAxisTickFormat(), $$.getXAxisTickValues());
axis = $$.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues);
}
$$.d3.select('body').append("g").style('visibility', 'hidden').call(axis).each(function () {
$$.d3.select(this).selectAll('text tspan').each(function () {
......@@ -278,8 +289,8 @@ c3_chart_internal_fn.getMaxTickWidth = function (id) {
});
}).remove();
}
$$.currentMaxTickWidth = maxWidth <= 0 ? $$.currentMaxTickWidth : maxWidth;
return $$.currentMaxTickWidth;
$$.currentMaxTickWidths[id] = maxWidth <= 0 ? $$.currentMaxTickWidths[id] : maxWidth;
return $$.currentMaxTickWidths[id];
};
c3_chart_internal_fn.updateAxisLabels = function (withTransition) {
......@@ -345,7 +356,7 @@ c3_chart_internal_fn.generateAxisTransitions = function (duration) {
};
};
c3_chart_internal_fn.redrawAxis = function (transitions, isHidden) {
var $$ = this;
var $$ = this, config = $$.config;
$$.axes.x.style("opacity", isHidden ? 0 : 1);
$$.axes.y.style("opacity", isHidden ? 0 : 1);
$$.axes.y2.style("opacity", isHidden ? 0 : 1);
......@@ -354,4 +365,8 @@ c3_chart_internal_fn.redrawAxis = function (transitions, isHidden) {
transitions.axisY.call($$.yAxis);
transitions.axisY2.call($$.y2Axis);
transitions.axisSubX.call($$.subXAxis);
// rotate tick text if needed
if (!config.axis_rotated && config.axis_x_tick_rotate) {
$$.rotateTickText($$.axes.x, transitions.axisX, config.axis_x_tick_rotate);
}
};
......@@ -97,19 +97,26 @@ function c3_axis(d3, params) {
tickOffset = tickX = 0;
}
var text, tspan, sizeFor1Char = getSizeFor1Char(tick), counts = [];
var text, tspan, sizeFor1Char = getSizeFor1Char(g.select('.tick')), counts = [];
var tickLength = Math.max(innerTickSize, 0) + tickPadding,
isVertical = orient === 'left' || orient === 'right';
// this should be called only when category axis
function splitTickText(d) {
var tickText = textFormatted(d) + "",
maxWidth = isVertical ? params.tickWidth : tickOffset * 2 - 10,
function splitTickText(d, maxWidth) {
var tickText = textFormatted(d),
subtext, spaceIndex, textWidth, splitted = [];
if (Object.prototype.toString.call(tickText) === "[object Array]") {
return tickText;
}
if (!maxWidth || maxWidth <= 0) {
maxWidth = isVertical ? 95 : params.isCategory ? (Math.ceil(scale1(ticks[1]) - scale1(ticks[0])) - 12) : 110;
}
function split(splitted, text) {
spaceIndex = undefined;
for (var i = 0; i < text.length; i++) {
for (var i = 1; i < text.length; i++) {
if (text.charAt(i) === ' ') {
spaceIndex = i;
}
......@@ -126,7 +133,7 @@ function c3_axis(d3, params) {
return splitted.concat(text);
}
return split(splitted, tickText);
return split(splitted, tickText + "");
}
function tspanDy(d, i) {
......@@ -135,7 +142,7 @@ function c3_axis(d3, params) {
if (orient === 'left' || orient === 'right') {
dy = -((counts[d.index] - 1) * (sizeFor1Char.h / 2) - (params.isCategory ? 2 : 3));
} else {
dy = params.isCategory ? ".40em" : ".71em";
dy = ".71em";
}
}
return dy;
......@@ -149,7 +156,7 @@ function c3_axis(d3, params) {
text = tick.select("text");
tspan = text.selectAll('tspan')
.data(function (d, i) {
var splitted = params.tickWidth ? splitTickText(d) : [].concat(textFormatted(d));
var splitted = params.tickMultiline ? splitTickText(d, params.tickWidth) : [].concat(textFormatted(d));
counts[i] = splitted.length;
return splitted.map(function (s) {
return { index: i, splitted: s };
......
......@@ -155,7 +155,7 @@ c3_chart_internal_fn.classChartArc = function (d) {
return CLASS.chartArc + this.classTarget(d.data.id);
};
c3_chart_internal_fn.getTargetSelectorSuffix = function (targetId) {
return targetId || targetId === 0 ? '-' + (targetId.replace ? targetId.replace(/([^a-zA-Z0-9-_])/g, '-') : targetId) : '';
return targetId || targetId === 0 ? ('-' + targetId).replace(/[\s?!@#$%^&*()_=+,.<>'":;\[\]/|~`{}\\]/g, '-') : '';
};
c3_chart_internal_fn.selectorTarget = function (id, prefix) {
return (prefix || '') + '.' + CLASS.target + this.getTargetSelectorSuffix(id);
......
......@@ -11,7 +11,7 @@ c3_chart_internal_fn.getAxisClipX = function (forHorizontal) {
return forHorizontal ? -(1 + left) : -(left - 1);
};
c3_chart_internal_fn.getAxisClipY = function (forHorizontal) {
return forHorizontal ? -20 : -4;
return forHorizontal ? -20 : -this.margin.top;
};
c3_chart_internal_fn.getXAxisClipX = function () {
var $$ = this;
......@@ -37,8 +37,7 @@ c3_chart_internal_fn.getAxisClipWidth = function (forHorizontal) {
return forHorizontal ? $$.width + 2 + left + right : $$.margin.left + 20;
};
c3_chart_internal_fn.getAxisClipHeight = function (forHorizontal) {
var $$ = this, config = $$.config;
return forHorizontal ? (config.axis_x_height ? config.axis_x_height : 0) + 80 : $$.height + 8;
return (forHorizontal ? this.margin.bottom : (this.margin.top + this.height)) + 8;
};
c3_chart_internal_fn.getXAxisClipWidth = function () {
var $$ = this;
......
......@@ -90,9 +90,10 @@ c3_chart_internal_fn.getDefaultConfig = function () {
axis_x_tick_count: undefined,
axis_x_tick_fit: true,
axis_x_tick_values: null,
axis_x_tick_rotate: undefined,
axis_x_tick_rotate: 0,
axis_x_tick_outer: true,
axis_x_tick_width: 80,
axis_x_tick_multiline: true,
axis_x_tick_width: null,
axis_x_max: undefined,
axis_x_min: undefined,
axis_x_padding: {},
......@@ -100,6 +101,7 @@ c3_chart_internal_fn.getDefaultConfig = function () {
axis_x_extent: undefined,
axis_x_label: {},
axis_y_show: true,
axis_y_type: undefined,
axis_y_max: undefined,
axis_y_min: undefined,
axis_y_center: undefined,
......@@ -108,6 +110,8 @@ c3_chart_internal_fn.getDefaultConfig = function () {
axis_y_tick_outer: true,
axis_y_tick_values: null,
axis_y_tick_count: undefined,
axis_y_tick_time_value: undefined,
axis_y_tick_time_interval: undefined,
axis_y_padding: {},
axis_y_default: undefined,
axis_y2_show: false,
......
......@@ -100,13 +100,20 @@ c3_chart_internal_fn.cloneTarget = function (target) {
})
};
};
c3_chart_internal_fn.updateXs = function () {
var $$ = this;
$$.xs = [];
$$.data.targets[0].values.forEach(function (v) {
$$.xs[v.index] = v.x;
});
};
c3_chart_internal_fn.getPrevX = function (i) {
var $$ = this, value = $$.getValueOnIndex($$.data.targets[0].values, i - 1);
return value ? value.x : null;
var x = this.xs[i - 1];
return typeof x !== 'undefined' ? x : null;
};
c3_chart_internal_fn.getNextX = function (i) {
var $$ = this, value = $$.getValueOnIndex($$.data.targets[0].values, i + 1);
return value ? value.x : null;
var x = this.xs[i + 1];
return typeof x !== 'undefined' ? x : null;
};
c3_chart_internal_fn.getMaxDataCount = function () {
var $$ = this;
......@@ -296,22 +303,34 @@ c3_chart_internal_fn.findClosestFromTargets = function (targets, pos) {
return $$.findClosest(candidates, pos);
};
c3_chart_internal_fn.findClosest = function (values, pos) {
var $$ = this, minDist, closest;
values.forEach(function (v) {
var $$ = this, minDist = 100, closest;
// find mouseovering bar
values.filter(function (v) { return v && $$.isBarType(v.id); }).forEach(function (v) {
var shape = $$.d3.select('.' + CLASS.bars + $$.getTargetSelectorSuffix(v.id) + ' .' + CLASS.bar + '-' + v.index).node();
if ($$.isWithinBar(shape)) {
closest = v;
}
});
// find closest point from non-bar
values.filter(function (v) { return v && !$$.isBarType(v.id); }).forEach(function (v) {
var d = $$.dist(v, pos);
if (d < minDist || ! minDist) {
if (d < minDist) {
minDist = d;
closest = v;
}
});
return closest;
};
c3_chart_internal_fn.dist = function (data, pos) {
var $$ = this, config = $$.config,
yScale = $$.getAxisId(data.id) === 'y' ? $$.y : $$.y2,
xIndex = config.axis_rotated ? 1 : 0,
yIndex = config.axis_rotated ? 0 : 1;
return Math.pow($$.x(data.x) - pos[xIndex], 2) + Math.pow(yScale(data.value) - pos[yIndex], 2);
yIndex = config.axis_rotated ? 0 : 1,
y = $$.circleY(data, data.index),
x = $$.x(data.x);
return Math.pow(x - pos[xIndex], 2) + Math.pow(y - pos[yIndex], 2);
};
c3_chart_internal_fn.convertValuesToStep = function (values) {
var converted = [].concat(values), i;
......
......@@ -55,9 +55,10 @@ c3_chart_internal_fn.updateXGrid = function (withoutUpdate) {
};
c3_chart_internal_fn.updateYGrid = function () {
var $$ = this, config = $$.config;
var $$ = this, config = $$.config,
gridValues = $$.yAxis.tickValues() || $$.y.ticks(config.grid_y_ticks);
$$.ygrid = $$.main.select('.' + CLASS.ygrids).selectAll('.' + CLASS.ygrid)
.data($$.y.ticks(config.grid_y_ticks));
.data(gridValues);
$$.ygrid.enter().append('line')
.attr('class', CLASS.ygrid);
$$.ygrid.attr("x1", config.axis_rotated ? $$.y : 0)
......@@ -69,7 +70,7 @@ c3_chart_internal_fn.updateYGrid = function () {
};
c3_chart_internal_fn.redrawGrid = function (duration, withY) {
c3_chart_internal_fn.redrawGrid = function (duration) {
var $$ = this, main = $$.main, config = $$.config,
xgridLine, ygridLine, yv;
......@@ -101,43 +102,41 @@ c3_chart_internal_fn.redrawGrid = function (duration, withY) {
.remove();
// Y-Grid
if (withY && config.grid_y_show) {
if (config.grid_y_show) {
$$.updateYGrid();
}
if (withY) {
$$.ygridLines = main.select('.' + CLASS.ygridLines).selectAll('.' + CLASS.ygridLine)
.data(config.grid_y_lines);
// enter
ygridLine = $$.ygridLines.enter().append('g')
.attr("class", function (d) { return CLASS.ygridLine + (d['class'] ? ' ' + d['class'] : ''); });
ygridLine.append('line')
.style("opacity", 0);
ygridLine.append('text')
.attr("text-anchor", "end")
.attr("transform", config.axis_rotated ? "rotate(-90)" : "")
.attr('dx', config.axis_rotated ? 0 : -$$.margin.top)
.attr('dy', -5)
.style("opacity", 0);
// update
yv = $$.yv.bind($$);
$$.ygridLines.select('line')
.transition().duration(duration)
.attr("x1", config.axis_rotated ? yv : 0)
.attr("x2", config.axis_rotated ? yv : $$.width)
.attr("y1", config.axis_rotated ? 0 : yv)
.attr("y2", config.axis_rotated ? $$.height : yv)
.style("opacity", 1);
$$.ygridLines.select('text')
.transition().duration(duration)
.attr("x", config.axis_rotated ? 0 : $$.width)
.attr("y", yv)
.text(function (d) { return d.text; })
.style("opacity", 1);
// exit
$$.ygridLines.exit().transition().duration(duration)
.style("opacity", 0)
.remove();
}
$$.ygridLines = main.select('.' + CLASS.ygridLines).selectAll('.' + CLASS.ygridLine)
.data(config.grid_y_lines);
// enter
ygridLine = $$.ygridLines.enter().append('g')
.attr("class", function (d) { return CLASS.ygridLine + (d['class'] ? ' ' + d['class'] : ''); });
ygridLine.append('line')
.style("opacity", 0);
ygridLine.append('text')
.attr("text-anchor", "end")
.attr("transform", config.axis_rotated ? "rotate(-90)" : "")
.attr('dx', config.axis_rotated ? 0 : -$$.margin.top)
.attr('dy', -5)
.style("opacity", 0);
// update
yv = $$.yv.bind($$);
$$.ygridLines.select('line')
.transition().duration(duration)
.attr("x1", config.axis_rotated ? yv : 0)
.attr("x2", config.axis_rotated ? yv : $$.width)
.attr("y1", config.axis_rotated ? 0 : yv)
.attr("y2", config.axis_rotated ? $$.height : yv)
.style("opacity", 1);
$$.ygridLines.select('text')
.transition().duration(duration)
.attr("x", config.axis_rotated ? 0 : $$.width)
.attr("y", yv)
.text(function (d) { return d.text; })
.style("opacity", 1);
// exit
$$.ygridLines.exit().transition().duration(duration)
.style("opacity", 0)
.remove();
};
c3_chart_internal_fn.addTransitionForGrid = function (transitions) {
var $$ = this, config = $$.config, xv = $$.xv.bind($$);
......@@ -202,7 +201,7 @@ c3_chart_internal_fn.getGridFilterToRemove = function (params) {
return params ? function (line) {
var found = false;
[].concat(params).forEach(function (param) {
if ((('value' in param && line.value === params.value) || ('class' in param && line['class'] === params['class']))) {
if ((('value' in param && line.value === param.value) || ('class' in param && line['class'] === param['class']))) {
found = true;
}
});
......
......@@ -59,6 +59,10 @@ c3_chart_internal_fn.updateEventRect = function (eventRectUpdate) {
}
else {
if (($$.isCustomX() || $$.isTimeSeries()) && !$$.isCategorized()) {
// update index for x that is used by prevX and nextX
$$.updateXs();
rectW = function (d) {
var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index);
......@@ -231,12 +235,20 @@ c3_chart_internal_fn.generateEventRectsForSingleX = function (eventRectEnter) {
.on('drag', function () { $$.drag(d3.mouse(this)); })
.on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
.on('dragend', function () { $$.dragend(); })
)
.on("dblclick.zoom", null);
);
};
c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter) {
var $$ = this, d3 = $$.d3, config = $$.config;
function mouseout() {
$$.svg.select('.' + CLASS.eventRect).style('cursor', null);
$$.hideXGridFocus();
$$.hideTooltip();
$$.unexpandCircles();
$$.unexpandBars();
}
eventRectEnter.append('rect')
.attr('x', 0)
.attr('y', 0)
......@@ -245,9 +257,7 @@ c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter)
.attr('class', CLASS.eventRect)
.on('mouseout', function () {
if ($$.hasArcType()) { return; }
$$.hideXGridFocus();
$$.hideTooltip();
$$.unexpandCircles();
mouseout();
})
.on('mousemove', function () {
var targetsToShow = $$.filterTargetsToShow($$.data.targets);
......@@ -259,7 +269,15 @@ c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter)
mouse = d3.mouse(this);
closest = $$.findClosestFromTargets(targetsToShow, mouse);
if (! closest) { return; }
if ($$.mouseover && (!closest || closest.id !== $$.mouseover.id)) {
config.data_onmouseout.call($$, $$.mouseover);
$$.mouseover = undefined;
}
if (! closest) {
mouseout();
return;
}
if ($$.isScatterType(closest) || !config.tooltip_grouped) {
sameXData = [closest];
......@@ -277,21 +295,18 @@ c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter)
if (config.point_focus_expand_enabled) {
$$.expandCircles(closest.index, closest.id, true);
}
$$.expandBars(closest.index, closest.id, true);
// Show xgrid focus line
$$.showXGridFocus(selectedData);
// Show cursor as pointer if point is close to mouse position
if ($$.dist(closest, mouse) < 100) {
if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
$$.svg.select('.' + CLASS.eventRect).style('cursor', 'pointer');
if (!$$.mouseover) {
config.data_onmouseover.call($$, closest);
$$.mouseover = true;
$$.mouseover = closest;
}
} else if ($$.mouseover) {
$$.svg.select('.' + CLASS.eventRect).style('cursor', null);
config.data_onmouseout.call($$, closest);
$$.mouseover = false;
}
})
.on('click', function () {
......@@ -306,8 +321,8 @@ c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter)
if (! closest) { return; }
// select if selection enabled
if ($$.dist(closest, mouse) < 100 && $$.toggleShape) {
$$.main.select('.' + CLASS.circles + $$.getTargetSelectorSuffix(closest.id)).select('.' + CLASS.circle + '-' + closest.index).each(function () {
if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
$$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).select('.' + CLASS.shape + '-' + closest.index).each(function () {
if (config.data_selection_grouped || $$.isWithinShape(this, closest)) {
$$.toggleShape(this, closest, closest.index);
$$.config.data_onclick.call($$.api, closest, this);
......@@ -320,8 +335,7 @@ c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter)
.on('drag', function () { $$.drag(d3.mouse(this)); })
.on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
.on('dragend', function () { $$.dragend(); })
)
.on("dblclick.zoom", null);
);
};
c3_chart_internal_fn.dispatchEvent = function (type, index, mouse) {
var $$ = this,
......
......@@ -74,6 +74,7 @@ c3_chart_internal_fn.toggleFocusLegend = function (targetIds, focus) {
c3_chart_internal_fn.revertLegend = function () {
var $$ = this, d3 = $$.d3;
$$.legend.selectAll('.' + CLASS.legendItem)
.classed(CLASS.legendItemFocused, false)
.transition().duration(100)
.style('opacity', function () { return $$.opacityForLegend(d3.select(this)); });
};
......@@ -107,7 +108,7 @@ c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
var l, totalLength = 0, offsets = {}, widths = {}, heights = {}, margins = [0], steps = {}, step = 0;
var withTransition, withTransitionForTransform;
var hasFocused = $$.legend.selectAll('.' + CLASS.legendItemFocused).size();
var texts, rects, tiles;
var texts, rects, tiles, background;
options = options || {};
withTransition = getOption(options, "withTransition", true);
......@@ -116,7 +117,7 @@ c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
function updatePositions(textElement, id, index) {
var reset = index === 0, isLast = index === targetIds.length - 1,
box = $$.getTextRect(textElement.textContent, CLASS.legendItem),
itemWidth = box.width + tileWidth + (isLast && !$$.isLegendRight ? 0 : paddingRight),
itemWidth = box.width + tileWidth + (isLast && !($$.isLegendRight || $$.isLegendInset) ? 0 : paddingRight),
itemHeight = box.height + paddingTop,
itemLength = $$.isLegendRight || $$.isLegendInset ? itemHeight : itemWidth,
areaLength = $$.isLegendRight || $$.isLegendInset ? $$.getLegendHeight() : $$.getLegendWidth(),
......@@ -225,9 +226,7 @@ c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
})
.on('mouseout', function (id) {
$$.d3.select(this).classed(CLASS.legendItemFocused, false);
if (!$$.transiting) {
$$.api.revert();
}
$$.api.revert();
if (config.legend_item_onmouseout) {
config.legend_item_onmouseout.call($$, id);
}
......@@ -251,13 +250,13 @@ c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
.attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegend)
.attr('width', 10)
.attr('height', 10);
// Set background for inset legend
if ($$.isLegendInset && maxWidth !== 0) {
$$.legend.insert('g', '.' + CLASS.legendItem)
background = $$.legend.select('.' + CLASS.legendBackground + ' rect');
if ($$.isLegendInset && maxWidth > 0 && background.size() === 0) {
background = $$.legend.insert('g', '.' + CLASS.legendItem)
.attr("class", CLASS.legendBackground)
.append('rect')
.attr('height', $$.getLegendHeight() - 12)
.attr('width', maxWidth * (step + 1) + 10);
.append('rect');
}
texts = $$.legend.selectAll('text')
......@@ -283,6 +282,12 @@ c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
.attr('x', xForLegend)
.attr('y', yForLegend);
if (background) {
(withTransition ? background.transition() : background)
.attr('height', $$.getLegendHeight() - 12)
.attr('width', maxWidth * (step + 1) + 10);
}
// toggle legend state
$$.legend.selectAll('.' + CLASS.legendItem)
.classed(CLASS.legendItemHidden, function (id) { return !$$.isTargetToShow(id); })
......
......@@ -39,7 +39,7 @@ c3_chart_internal_fn.getX = function (min, max, domain, offset) {
return scale;
};
c3_chart_internal_fn.getY = function (min, max, domain) {
var scale = this.getScale(min, max);
var scale = this.getScale(min, max, this.isTimeSeriesY());
if (domain) { scale.domain(domain); }
return scale;
};
......
......@@ -52,14 +52,14 @@ c3_chart_internal_fn.getBarW = function (axis, barTargetsNum) {
w = typeof config.bar_width === 'number' ? config.bar_width : barTargetsNum ? (axis.tickOffset() * 2 * config.bar_width_ratio) / barTargetsNum : 0;
return config.bar_width_max && w > config.bar_width_max ? config.bar_width_max : w;
};
c3_chart_internal_fn.getBars = function (i) {
c3_chart_internal_fn.getBars = function (i, id) {
var $$ = this;
return $$.main.selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
return (id ? $$.main.selectAll('.' + CLASS.bars + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
};
c3_chart_internal_fn.expandBars = function (i, id, reset) {
var $$ = this;
if (reset) { $$.unexpandBars(); }
$$.getBars(i).classed(CLASS.EXPANDED, true);
$$.getBars(i, id).classed(CLASS.EXPANDED, true);
};
c3_chart_internal_fn.unexpandBars = function (i) {
var $$ = this;
......@@ -112,8 +112,7 @@ c3_chart_internal_fn.generateGetBarPoints = function (barIndices, isSub) {
};
};
c3_chart_internal_fn.isWithinBar = function (that) {
var d3 = this.d3,
mouse = d3.mouse(that), box = that.getBoundingClientRect(),
var mouse = this.d3.mouse(that), box = that.getBoundingClientRect(),
seg0 = that.pathSegList.getItem(0), seg1 = that.pathSegList.getItem(1),
x = Math.min(seg0.x, seg1.x), y = Math.min(seg0.y, seg1.y),
w = box.width, h = box.height, offset = 2,
......
......@@ -289,7 +289,7 @@ c3_chart_internal_fn.redrawCircle = function () {
.attr("r", $$.pointR.bind($$))
.style("fill", $$.color);
$$.mainCircle
.style("opacity", $$.initialOpacity.bind($$));
.style("opacity", $$.initialOpacityForCircle.bind($$));
$$.mainCircle.exit().remove();
};
c3_chart_internal_fn.addTransitionForCircle = function (transitions, cx, cy) {
......@@ -306,10 +306,19 @@ c3_chart_internal_fn.addTransitionForCircle = function (transitions, cx, cy) {
c3_chart_internal_fn.circleX = function (d) {
return d.x || d.x === 0 ? this.x(d.x) : null;
};
c3_chart_internal_fn.circleY = function (d, i) {
var $$ = this,
lineIndices = $$.getShapeIndices($$.isLineType), getPoints = $$.generateGetLinePoints(lineIndices);
return $$.config.data_groups.length > 0 ? getPoints(d, i)[0][1] : $$.getYScale(d.id)(d.value);
c3_chart_internal_fn.updateCircleY = function () {
var $$ = this, lineIndices, getPoints;
if ($$.config.data_groups.length > 0) {
lineIndices = $$.getShapeIndices($$.isLineType),
getPoints = $$.generateGetLinePoints(lineIndices);
$$.circleY = function (d, i) {
return getPoints(d, i)[0][1];
};
} else {
$$.circleY = function (d) {
return $$.getYScale(d.id)(d.value);
};
}
};
c3_chart_internal_fn.getCircles = function (i, id) {
var $$ = this;
......
......@@ -15,14 +15,14 @@ c3_chart_internal_fn.getCurrentPaddingBottom = function () {
var config = this.config;
return isValue(config.padding_bottom) ? config.padding_bottom : 0;
};
c3_chart_internal_fn.getCurrentPaddingLeft = function () {
c3_chart_internal_fn.getCurrentPaddingLeft = function (withoutRecompute) {
var $$ = this, config = $$.config;
if (isValue(config.padding_left)) {
return config.padding_left;
} else if (config.axis_rotated) {
return !config.axis_x_show ? 1 : Math.max(ceil10($$.getAxisWidthByAxisId('x')), 40);
return !config.axis_x_show ? 1 : Math.max(ceil10($$.getAxisWidthByAxisId('x', withoutRecompute)), 40);
} else {
return !config.axis_y_show ? 1 : ceil10($$.getAxisWidthByAxisId('y'));
return !config.axis_y_show ? 1 : ceil10($$.getAxisWidthByAxisId('y', withoutRecompute));
}
};
c3_chart_internal_fn.getCurrentPaddingRight = function () {
......@@ -57,29 +57,33 @@ c3_chart_internal_fn.getParentHeight = function () {
};
c3_chart_internal_fn.getSvgLeft = function () {
c3_chart_internal_fn.getSvgLeft = function (withoutRecompute) {
var $$ = this, config = $$.config,
leftAxisClass = config.axis_rotated ? CLASS.axisX : CLASS.axisY,
leftAxis = $$.main.select('.' + leftAxisClass).node(),
svgRect = leftAxis ? leftAxis.getBoundingClientRect() : {right: 0},
chartRect = $$.selectChart.node().getBoundingClientRect(),
hasArc = $$.hasArcType(),
svgLeft = svgRect.right - chartRect.left - (hasArc ? 0 : $$.getCurrentPaddingLeft());
svgLeft = svgRect.right - chartRect.left - (hasArc ? 0 : $$.getCurrentPaddingLeft(withoutRecompute));
return svgLeft > 0 ? svgLeft : 0;
};
c3_chart_internal_fn.getAxisWidthByAxisId = function (id) {
c3_chart_internal_fn.getAxisWidthByAxisId = function (id, withoutRecompute) {
var $$ = this, position = $$.getAxisLabelPositionById(id);
return position.isInner ? 20 + $$.getMaxTickWidth(id) : 40 + $$.getMaxTickWidth(id);
return $$.getMaxTickWidth(id, withoutRecompute) + (position.isInner ? 20 : 40);
};
c3_chart_internal_fn.getHorizontalAxisHeight = function (axisId) {
var $$ = this, config = $$.config;
var $$ = this, config = $$.config, h = 30;
if (axisId === 'x' && !config.axis_x_show) { return 8; }
if (axisId === 'x' && config.axis_x_height) { return config.axis_x_height; }
if (axisId === 'y' && !config.axis_y_show) { return config.legend_show && !$$.isLegendRight && !$$.isLegendInset ? 10 : 1; }
if (axisId === 'y2' && !config.axis_y2_show) { return $$.rotated_padding_top; }
return ($$.getAxisLabelPositionById(axisId).isInner ? 30 : 40) + (axisId === 'y2' ? -10 : 0);
// Calculate x axis height when tick rotated
if (axisId === 'x' && !config.axis_rotated && config.axis_x_tick_rotate) {
h = $$.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_x_tick_rotate) / 180);
}
return h + ($$.getAxisLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0);
};
c3_chart_internal_fn.getEventRectWidth = function () {
......
......@@ -19,7 +19,7 @@ c3_chart_internal_fn.initSubchart = function () {
// Define g for chart area
context.append('g')
.attr("clip-path", $$.clipPath)
.attr("clip-path", $$.clipPathForSubchart)
.attr('class', CLASS.chart);
// Define g for bar chart area
......
......@@ -32,7 +32,7 @@ c3_chart_internal_fn.redrawText = function (durationForExit) {
.style("fill", function (d) { return $$.color(d); })
.style("fill-opacity", 0);
$$.mainText
.text(function (d) { return $$.formatByAxisId($$.getAxisId(d.id))(d.value, d.id); });
.text(function (d, i, j) { return $$.formatByAxisId($$.getAxisId(d.id))(d.value, d.id, i, j); });
$$.mainText.exit()
.transition().duration(durationForExit)
.style('fill-opacity', 0)
......
......@@ -67,27 +67,29 @@ c3_chart_internal_fn.showTooltip = function (selectedData, mouse) {
tooltipLeft = ($$.width / 2) + mouse[0];
tooltipTop = ($$.height / 2) + mouse[1] + 20;
} else {
svgLeft = $$.getSvgLeft(true);
if (config.axis_rotated) {
svgLeft = $$.getSvgLeft();
tooltipLeft = svgLeft + mouse[0] + 100;
tooltipRight = tooltipLeft + tWidth;
chartRight = $$.getCurrentWidth() - $$.getCurrentPaddingRight();
chartRight = $$.currentWidth - $$.getCurrentPaddingRight();
tooltipTop = $$.x(dataToShow[0].x) + 20;
} else {
svgLeft = $$.getSvgLeft();
tooltipLeft = svgLeft + $$.getCurrentPaddingLeft() + $$.x(dataToShow[0].x) + 20;
tooltipLeft = svgLeft + $$.getCurrentPaddingLeft(true) + $$.x(dataToShow[0].x) + 20;
tooltipRight = tooltipLeft + tWidth;
chartRight = svgLeft + $$.getCurrentWidth() - $$.getCurrentPaddingRight();
chartRight = svgLeft + $$.currentWidth - $$.getCurrentPaddingRight();
tooltipTop = mouse[1] + 15;
}
if (tooltipRight > chartRight) {
tooltipLeft -= tooltipRight - chartRight;
}
if (tooltipTop + tHeight > $$.getCurrentHeight() && tooltipTop > tHeight + 30) {
if (tooltipTop + tHeight > $$.currentHeight) {
tooltipTop -= tHeight + 30;
}
}
if (tooltipTop < 0) {
tooltipTop = 0;
}
// Set tooltip
$$.tooltip
.style("top", tooltipTop + "px")
......
c3_chart_internal_fn.initZoom = function () {
var $$ = this, d3 = $$.d3, config = $$.config;
var $$ = this, d3 = $$.d3, config = $$.config, startEvent;
$$.zoom = d3.behavior.zoom()
.on("zoomstart", function () {
startEvent = d3.event.sourceEvent;
$$.zoom.altDomain = d3.event.sourceEvent.altKey ? $$.x.orgDomain() : null;
config.zoom_onzoomstart.call($$.api, d3.event.sourceEvent);
})
......@@ -10,6 +11,11 @@ c3_chart_internal_fn.initZoom = function () {
$$.redrawForZoom.call($$);
})
.on('zoomend', function () {
var event = d3.event.sourceEvent;
// if click, do nothing. otherwise, click interaction will be canceled.
if (event && startEvent.x === event.x && startEvent.y === event.y) {
return;
}
$$.redrawEventRect();
$$.updateZoom();
config.zoom_onzoomend.call($$.api, $$.x.orgDomain());
......@@ -30,8 +36,8 @@ c3_chart_internal_fn.initZoom = function () {
};
c3_chart_internal_fn.updateZoom = function () {
var $$ = this, z = $$.config.zoom_enabled ? $$.zoom : function () {};
$$.main.select('.' + CLASS.zoomRect).call(z);
$$.main.selectAll('.' + CLASS.eventRect).call(z);
$$.main.select('.' + CLASS.zoomRect).call(z).on("dblclick.zoom", null);
$$.main.selectAll('.' + CLASS.eventRect).call(z).on("dblclick.zoom", null);
};
c3_chart_internal_fn.redrawForZoom = function () {
var $$ = this, d3 = $$.d3, config = $$.config, zoom = $$.zoom, x = $$.x;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment