我正在使用Chart.js,我想知道在单击饼图的一部分时是否有办法过滤条形图。有没有办法在Chart.js中过滤数据?
回答
使用dc.js:https://dc-js.github.io/dc.js/
它已经完全的功能要求。
由于这是一个chart.js之问题:-),你这是怎么做到这一点chart.js之(这不是太复杂,要么)
设置饼图
// pie
var data = [
{
value: 300,
color: "#F7464A",
highlight: "#FF5A5E",
label: "Red",
subData: [28, 48, 40, 19, 86, 27, 190]
}, {
value: 50,
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green",
subData: [90, 28, 48, 40, 19, 86, 127]
}, {
value: 100,
color: "#FDB45C",
highlight: "#FFC870",
label: "Yellow",
subData: [28, 48, 40, 19, 86, 27, 190]
}
]
var canvas = document.getElementById("chart");
var ctx = canvas.getContext("2d");
var myPieChart = new Chart(ctx).Pie(data);
设置使用饼图数据
// bar using pie's sub data
var bardata = {
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
datasets: [
{
label: "My Second dataset",
fillColor: "rgba(151,187,205,0.5)",
strokeColor: "rgba(151,187,205,0.8)",
highlightFill: "rgba(151,187,205,0.75)",
highlightStroke: "rgba(151,187,205,1)",
data: data[0].subData.map(function (point, i) {
var pointTotal = 0;
data.forEach(function (point) {
pointTotal += point.subData[i]
})
return pointTotal;
})
}
]
};
var subcanvas = document.getElementById("subchart")
var subctx = subcanvas.getContext("2d");
var myBarChart = new Chart(subctx).Bar(bardata);
Updatin条形图点击饼图
// connect them both
canvas.onclick = function (evt) {
var activeSector = myPieChart.getSegmentsAtEvent(evt);
myBarChart.datasets[0].bars.forEach(function (bar, i) {
var pointTotal = 0;
data.forEach(function (point, j) {
if (activeSector.length === 0 || point.label === activeSector[0].label)
pointTotal += data[j].subData[i]
})
bar.value = pointTotal;
});
myBarChart.update();
};
点击(在饼图的画布但)馅饼外时克酒吧数据复位条形图。
已经张贴其他的答案包括什么,我会一般建议这里是使用DC-JS如果你想crossfilter启用图表出了大门。我会评论这个答案,但我没有足够的声誉,所以我发布这个选项'c。)',其中'a。)'正在使用dc-js和'b。)'进行一些修改到现有的Chart.js图表。
选项'c。)'用于扩展Chart.js图表类型并使子图表像DC-js图表一样工作。 Chart.js图表类型遵循继承层次结构,因此如果您喜欢已经存在的图表,则可以使用自己的原型方法来包装其原型方法。此选项非常重要,在标题为“dc.js - 侦听图表组渲染”的堆栈溢出问题的选定答案中,描述了dc-js的chartRegistry对象的当前实现如何与d3或dc内部相当分离,所以任何实现chartRegistry接口的图表都可以成为chartGroup的一部分。
我当时非常希望在数据集中使用Polar Area Charts,因为我已经在使用一个充满了dc-js图表的图表组来交叉过滤数据。我为Polar Area图表编写了一个扩展,它可以作为一种方式的示例(我将继续说并不是最好的方式),以便像dc-js一样扩展图表类型。这样做的回购是https://github.com/nsubordin81/Chart.dc.js,麻省理工学院的许可协议进行许可,并且如果是有史以来去任何地方,所有的代码被复制到例如小提琴:http://jsfiddle.net/nsubordin81/3w725o3c/1/
Chart.dc.js v 0.1.0
MIT许可:opensource.org/licenses/MIT 版权所有(C)2015年泰勒鸟
(function() {
"use strict";
var root = this,
Chart = root.Chart,
dc = root.dc,
helpers = Chart.helpers,
//class for data structure that manages filters as they relate to chart segments. This should probably be generalized to chart elements of all kinds.
FilterManager = function (segmentList) {
//private member variable
var filterMap = [];
//constructor
//accepts a list of SegmentArcs that have had the extra properties added to them
for (var i = 0; i < segmentList.length; i++) {
add(segmentList[i].segmentID);
}
//private methods
function testOnAll(test) {
var testResult = true;
for (var i = 0; i < filterMap.length; i++) {
//one failure of test means testOnAll fails
if (!test(filterMap[i])) {
testResult = false;
}
}
return testResult;
}
//add a filter, pretty much just a wrapper for push
function add(segmentID) {
filterMap.push({
"segmentID": segmentID,
"active": false
});
}
//remove a filter by id, returns removed filter
function remove(segmentID) {
var removed = filterMap.find(segmentID);
filterMap = filterMap.filter(function (elem) {
return elem.segmentID !== segmentID;
});
return removed;
}
//return this segment if it is filtered
function find(segmentID) {
for (var i = 0; i < filterMap.length; i++) {
if (filterMap[i].segmentID === segmentID) {
return filterMap[i];
}
}
return -1;
}
//public methods
return {
//tell me if the filter for this segment is active
isActive: function (segmentID) {
var filter = find(segmentID);
if (filter === -1) {
console.error("something went wrong, the filter for this segment does not exist");
}
return filter.active;
},
//for the given segment, activate or deactivate its filter. return whether the filter is on or off.
flip: function (segmentID) {
var filter = find(segmentID);
if (filter === -1) {
console.error("something went wrong, the filter for this segment does not exist");
}
filter.active ? filter.active = false : filter.active = true;
return filter.active;
},
//if all filters are on, we want to be able to quickly deactivate them all
turnAllOff: function() {
for (var i = 0; i < filterMap.length; i++) {
filterMap[i].active = false;
}
},
//tell me if all of the filters are off
allOff: function() {
return testOnAll(function (elem) {
return !elem.active;
});
},
//tell me if all the filters are on
allOn: function() {
return testOnAll(function (elem) {
return elem.active;
});
}
}
};
//utility function, Takes an array that has some property as its key
//and forms a javascript object with the keys as properties so we can get O(1) access
function createKeyMap(arr, propName) {
var keyMap = {}
for (var i = 0; i < arr.length; i++) {
keyMap[arr[i][propName]] = arr[i];
}
return keyMap;
}
Chart.types.PolarArea.extend({
name: "PolarAreaXF",
//this will have to be a member
dimension: undefined,
colorTypes: {
"NORMAL": 0,
"HIGHLIGHT": 1,
"FILTER": 2,
"FILTER_HIGHLIGHT": 3
},
chartGroup: undefined,
filters: undefined,
originalDataKeys: undefined,
initialize: function (data) {
//--PRE--
var that = this;
//Polar Area initialize method is expecting (data, options) in arguments,
//but we pass in an array of components to merge. Let's clean this up.
var argsArray = Array.prototype.slice.call(arguments);
//remove the first element of arguments which is our array, then we do a bunch of Chartjs converison on it . . .
argsArray.splice(0, 1);
//TODO - check if data is an array, if not, put a message in a console explaining how you are supposed to send data in an array
this.dimension = data.dimension;
data.chartGroup ? this.chartGroup = data.chartGroup : this.chartGroup = 0;
//short but magical line. Now we are linked with all dc charts in this group!
dc.registerChart(this, this.chartGroup);
var data = this.setupChartData(data.colors, data.highlights, data.labels);
//... and push the result in its place.
argsArray.unshift(data);
//originalDataArray -- this is used as a reference to the original state of the chart, since segments can come and go,
//we use this to track what a segment's original colors were when adding it back in. This would mess up adding a truly new segment, but who
//is gonna do that? Assumption here is dimensions start with so many groups and that is it.
this.originalDataKeys = createKeyMap(data, "key");
//parent's initialize
Chart.types.PolarArea.prototype.initialize.apply(this, argsArray);
//--modify SegmentArcs--
//assign colors and ids to all existing segment arcs
var mySegments = this.segments;
for (var i = 0; i < mySegments.length; i++) {
mySegments[i].colorList = [undefined, undefined, "#777", "#aaa"];
mySegments[i].colorList[this.colorTypes.NORMAL] = mySegments[i].fillColor;
mySegments[i].colorList[this.colorTypes.HIGHLIGHT] = mySegments[i].highlight;
mySegments[i].segmentID = i;
mySegments[i].key = data[i].key;
}
//add methods to SegmentArc objects that will color them one way or the other depending on their filter
this.SegmentArc.prototype.setIncluded = function (include) {
if (include) {
this.fillColor = this.colorList[that.colorTypes.NORMAL];
this.highlight = this.colorList[that.colorTypes.HIGHLIGHT];
} else {
this.fillColor = this.colorList[that.colorTypes.FILTER];
this.highlight = this.colorList[that.colorTypes.FILTER_HIGHLIGHT];
}
}
//--initialize filters--
this.filters = new FilterManager(this.segments);
//handle clicks on segments as filter events, do the styling and crossfilter changes at the Chart level in the filter method.
helpers.bindEvents(this, ["mousedown"], function (evt) {
var activeSegment = Chart.types.PolarArea.prototype.getSegmentsAtEvent.apply(this, [evt])[0];
this.handleFilter(activeSegment);
});
},
//convert crossfilter dimension into chart.js Polar Area data object array
setupChartData: function (colors, highlights, labels) {
var chartJSible = [];
//probably need checks here to make sure client actually passed in a crossfilter dimension
var grouped = this.dimension.group().reduceCount().top(Infinity);
//probably need checks here to either fail if the arrays aren't all long enough or have some way to add random colors/highlights if they are shorter.
for (var i = 0; i < grouped.length; i++) {
var dataObject = {
value: grouped[i].value,
key: grouped[i].key,
color: colors[i],
highlight: highlights[i],
label: labels ? (labels[i] ? labels[i] : grouped[i].key) : grouped[i].key
};
chartJSible.push(dataObject);
}
return chartJSible;
},
//figure out what changed between Chart.js' internally maintained data object array and crossfilter's dimension data. use the saved information
//about what colors and highlight a key has to rebuild the segmentArc list 'segments'. can't trash the old, it might mess up the animations.
redraw: function() {
var grouped = this.dimension.group().reduceCount().top(Infinity);
var currentSegmentKeys = createKeyMap(this.segments, "key");
var crossfilterGroupKeys = createKeyMap(grouped, "key");
//loop through the segment list, if the segment for a group is already there, update the value, if it is not there, add it back using the
//original data as a guide for what it's color and highlight color should be. if there are segments in the existing list
var length = Math.max(this.segments.length, grouped.length);
//going through both lists, whichever is longer
for (var i = 0; i < length; i++) {
var sList = this.segments;
var gList = grouped;
//only do this part if we still have items in the new filtered list
if (gList[i]) {
//we already have a segment for this crossfilter group, just get that segment and update its value
if (currentSegmentKeys[gList[i].key]) {
currentSegmentKeys[gList[i].key].value = gList[i].value;
} else {
//the chart doesn't have the crossfilter group item, add a new segment with the right colors and values from original data
var theSegment = this.originalDataKeys[gList[i].key];
this.addData(theSegment, 0, true);
}
}
//only do this part if we still have items in the current chart segment list
if (sList[i]) {
//we don't have this segment in the new crossfilter group, remove it from the chart
if (!crossfilterGroupKeys[sList[i].key]) {
this.removeData(i);
}
}
}
this.update();
},
filterAll: function() {
this.dimension.filterAll();
this.filters.turnAllOff();
this.colorMeIn();
this.redraw();
},
handleFilter: function (clicked) {
//after we have all of the filters figured out, change the colors to reflect what they should be and update the chart
this.filters.flip(clicked.segmentID);
this.colorMeIn();
if (this.filters.allOn()) {
this.dimension = this.dimension.filterAll();
dc.redrawAll(this.chartGroup);
this.filters.turnAllOff();
}
dc.redrawAll(this.chartGroup);
},
colorMeIn() {
var activeFilters = [];
var segments = this.segments;
for (var i = 0; i < segments.length; i++) {
var segment = segments[i];
if (this.filters.isActive(segment.segmentID) || this.filters.allOff()) {
segment.setIncluded(true);
activeFilters.push(segment.key);
} else {
segment.setIncluded(false);
}
}
this.dimension = this.dimension.filterFunction(function (d) {
for (var i = 0; i < activeFilters.length; i++) {
if (d === activeFilters[i]) {
return true;
}
}
return false;
});
}
})
}).call(this);
- 1. 有没有办法异步过滤IList?
- 2. 有没有办法在DataView上使用参数化过滤器?
- 3. 有没有办法在数据表的过滤开始时忽略空格?
- 4. 有没有办法通过值列表来过滤Salesforce报表?
- 5. 有没有办法有条件地添加过滤器内联?
- 6. 有没有办法过滤jQuery中没有触发事件的匹配元素?
- 7. 有没有办法unfork heroku数据库
- 8. 有没有办法保存HSQLDB数据?
- 9. 有没有办法使用chart.js绘制浮动矩形
- 10. 有没有办法用AutoMapper进行过滤?
- 11. 有没有办法过滤掉数组中出现多次的元素?
- 12. 有没有办法在Oz中存储函数/过程调用?
- 13. 有没有办法通过枚举在Rust中索引数组?
- 14. 有没有办法通过EOF读取HD数据?
- 15. 有没有办法通过编写PHP来生成数据库?
- 16. 有没有办法绕过AuditingEntityListener为测试设置数据?
- 17. 有没有办法在django管理过滤器中选择多个选项?
- 18. 有没有办法在ServiceStack Redis中使用Redis MONITOR数据?
- 19. 有没有办法在android中限制数据库条目?
- 20. 有没有办法在php中清除表单数据?
- 21. 有没有办法在NetBeans
- 22. 有没有办法在Notepad ++
- 23. 有没有办法在UIWebview
- 24. 有没有办法在一个数组
- 25. 有没有办法在一个数组
- 26. 有没有办法插入没有数据的行
- 27. 有没有办法在编译时有值的元数据?
- 28. 有没有办法搜索mySQL数据库中的所有表?
- 29. 有没有办法在Pymongo 3.0中跳过insert_many的现有_id?
- 30. 在symfony中有没有办法让一个没有数据库的实体?
谢谢!有没有什么方法可以显示“过滤量”背后的“全额”?像http://i.imgur.com/4gTXNFK.gif一样 –