我正在使用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. 有沒有辦法從根目錄過濾數據?
- 3. 有沒有辦法在DataView上使用參數化過濾器?
- 4. 有沒有辦法在django admin中過濾查詢集?
- 5. 有沒有辦法在Excel中調整/擴展過濾列表?
- 6. 有沒有辦法在數據表的過濾開始時忽略空格?
- 7. 有沒有辦法通過值列表來過濾Salesforce報表?
- 8. 有沒有辦法過濾頁面上的所有內容?
- 9. 有沒有辦法有條件地添加過濾器內聯?
- 10. 有沒有辦法從控制器獲取數據到過濾器?
- 11. 有沒有辦法從數據庫中過期文件?
- 12. 有沒有辦法過濾jQuery中沒有觸發事件的匹配元素?
- 13. 有沒有辦法保存HSQLDB數據?
- 14. 有沒有辦法unfork heroku數據庫
- 15. 有沒有辦法壓縮DICOM數據?
- 16. 有沒有辦法使用chart.js繪製浮動矩形
- 17. 有沒有辦法預先過濾powerBI報告服務器端?
- 18. 有沒有辦法過濾特定類別的log4j日誌
- 19. 有沒有辦法強制RestAssured過濾器的順序?
- 20. 有沒有辦法用AutoMapper進行過濾?
- 21. 有沒有辦法用css過濾掉隱藏的元素?
- 22. 有沒有辦法模仿photoshop的CSS疊加過濾器?
- 23. 有沒有辦法只運行一次servlet過濾?
- 24. 有沒有辦法過濾Twilio通話記錄?
- 25. 有沒有辦法過濾掉數組中出現多次的元素?
- 26. 有沒有辦法在Oz中存儲函數/過程調用?
- 27. 有沒有辦法通過枚舉在Rust中索引數組?
- 28. 有沒有辦法通過EOF讀取HD數據?
- 29. 有沒有辦法繞過AuditingEntityListener爲測試設置數據?
- 30. 有沒有辦法通過編寫PHP來生成數據庫?
謝謝!有沒有什麼方法可以顯示「過濾量」背後的「全額」?像http://i.imgur.com/4gTXNFK.gif一樣 –