-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHorizontalBarChartEngine.js
282 lines (250 loc) · 11.6 KB
/
HorizontalBarChartEngine.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
// #region MetaData
// This function using to draw Horizontal Bar Chart, and return object that contains object for each part of chart,
// you can use those objects to make your chart resposive.
// In the engine event on legendClick and part of slices based on yScale labels Clicked,
// IF you want to override all functionality of event you can using those signatures to create your functions:
// function OnMouseLegendClick(d, i){} => for lengend event Clicked
// function OnMouseBarChartClicked(d, i){} => for each part of slices based on yScale labels Clicked
// IF you want to increase some of your functionality for main functionality of each event you can using those signatures to create your functions:
// function CLickDownLegend(d, i){} => for Legend event clicked this fired when clicked down only on each part of legend
// function ClickUpLegend(d, i){} => for Legend event clicked this fired when clicked Up only on each part of legend
// You can use the above two methods to subscribe all event of legend event (DOWN/UP)
// function CLickDownBarChart(d, i){} => for partOFBarChart based on YScale labels, event clicked this fired when clicked down only on each part of legend
// function ClickUpBarChart(d, i){} => for partOFBarChart based on YScale labels, event clicked this fired when clicked down only on each part of legend
// It take an object that contains some of property that using to draw the chart:
// 1- divClassName: it is a mandatory you set class name of DIV which is want to draw the chart in it
// 2- height: it is a mandatory, it set a height of main SVG
// 3- SVG: it is an optional property, you can set it with exist SVG object ,if you draw exist chart and want to draw new chart above it
// 4- NumberOfSlice: It is a mandatory , it is a number of slices that you want to draw its with the chart
// 5- xScaleMaxNumber: It is a mandatory, it is a max number that using to draw Scale
// 6- dataSet: It is a mandatory , it must contains some of property as:
// {Label: 'Label 01' ,ClassName: 'A A01' , ValueItem0: 22 , ValueItem1: 34 , ....},
// {Label: 'Label 01' ,ClassName:'B', ValueItem0: 25 , ValueItem1: 55 , ....}
// Label => Items that occurs in yScale
// ValueItem0 / ValueItem1 / ValueItem[n] => Its are Values of Slices , each ValueItem[n] act as Slice of all YScale.
// ClassName => If you want to add class name for each slice
// 7- title: It is an optional, you can set Title for Chart
// 8- colors: It is a mandatory, set it as array of colors that you want to using those to color slices
// 9- dataLegend: It is an optional , you can set it if you want to show Legned, but you must set array of names in order as order of slices as
// ['valueItem1' , 'valueItem2' , ...] each value here must be name that you want to occure in legend and much each slice
// 10- xScaleTitle: It is an optional, you can set it with string value if you want to occure title for XScale
// 11- yScaleTitle: It is an optional, you can set it with string value if you want to occure title for YScale
// 12- ShowLabels: It is an optional , you can set it with TRUE if you want to show values of each slice with it.
// 13- ShowXScale: It is an optional , you can set it with TRUE if you want to show XLine.
// 14- ShowYScale: It is an optional , you can set it with TRUE if you want to show YLine.
// 15- HiddenYTips: It is an optional, you can set it if you want to hidden the lines of YScale
// 16- HiddenXTips: It is an optional, you can set it if you want to hidden the lines of XScale
// 17- showVerticalLines: It is an optional, you can set it with true if you want to draw Vertical Lines
// #endregion
function DrawHorizontalBarChart({ divClassName, height, SVG, NumberOfSlice, xScaleMaxNumber, dataSet, title, colors, dataLegend, xScaleTitle, yScaleTitle, ShowLabels = false, ShowXScale = false, ShowYScale = false, HiddenYTips = false, HiddenXTips = false, showVerticalLines = false }) {
let result = {};
// #region MAin SVG
let color = d3.scaleOrdinal(colors);
let svgWidth;
let svgBar;
// let height = height;
if (SVG == undefined) {
svgBar = d3.select("." + divClassName)
.append("svg")
.attr('class', 'svgBar')
.attr("height", height)
} else {
svgBar = SVG;
}
svgWidth = parseInt(svgBar.style("width").substring(0, svgBar.style("width").length - 2));
result.SVG = svgBar;
result.SvgWidth = svgWidth;
// #endregion
// #region XScale && YScale
let xScale = d3.scaleLinear()
.domain([0, xScaleMaxNumber])
.range([0, svgWidth - 150]);
if (ShowXScale) {
let gXScale = svgBar.append("g")
.attr('class', "xScale")
.attr("transform", 'translate(100 , ' + (height - 50) + ')')
.call(d3.axisBottom(xScale));
result.gXScale = gXScale;
}
if (xScaleTitle != undefined) {
let gXScaleTitle = svgBar.append("g")
.attr('class', "xScaleTitle")
.attr("transform", 'translate(' + (svgWidth / 2) + ' , ' + (height - 10) + ')')
.append('text')
.text(xScaleTitle);
result.xScaleTitle = gXScaleTitle;
}
let yScale = d3.scaleBand()
.domain(dataSet.map((d) => d.Label))
.range([30, height - 100])
.padding(0.1)
if (ShowYScale) {
let gYScale = svgBar.append("g")
.attr('class', "yScale")
.attr("transform", 'translate(100 , ' + 50 + ')')
.call(d3.axisLeft(yScale));
result.gYScale = gYScale;
}
if (yScaleTitle != undefined) {
let gYScaleTitle = svgBar.append("g")
.attr('class', "yScaleTitle")
.attr("transform", 'translate(20 , ' + (height / 2) + ')')
.append('text')
.text(yScaleTitle)
.attr('transform', 'rotate(-90)');
result.yScaleTitle = gYScaleTitle;
}
// #endregion
// #region showVerticalLines
if (showVerticalLines) {
let gBarLine = svgBar.append('g')
.attr('class', 'gBarLine')
.attr("transform", 'translate(100 , ' + 80 + ')')
for (let index = 0; index < xScale.ticks().length; index++) {
gBarLine.append('line')
.attr('transform', d3.selectAll(".xScale .tick")._groups[0][index].getAttribute("transform"))
.attr('y2', (height - 130))
.attr('stroke', 'gray')
.attr('opacity', '0.2')
}
}
// #endregion
// #region Title
if (title != undefined) {
let gBarTitle = svgBar.append('text')
.attr('class', 'gBarTitle')
.attr("transform", 'translate(' + ((svgWidth / 2) - 250) + ' , ' + 30 + ')')
.text(title)
.attr('font-size', '12')
.attr('font-weight', 'bold');
result.gBarTitle = gBarTitle;
}
// #endregion
// #region Draw Bar Chart
let prevIndex = 0;
for (let index = 1; index <= NumberOfSlice; index++) {
let gBarChart = svgBar.append("g")
.attr('class', 'gBarChart')
.attr("transform", 'translate(100 , ' + (50) + ')');
gBarChart.selectAll('.g' + dataLegend[index - 1])
.data(dataSet)
.enter()
.append('rect')
.attr("class", (d) => (dataLegend != undefined ? dataLegend[index - 1] : '') + ' BarChat ' + d.Label.replace(/\s/g, '') + ' ' + (d.ClassName != undefined ? d.ClassName : ''))
.attr("x", 0)
.attr("y", (d) => yScale(d.Label) + (index == prevIndex ? ((yScale.bandwidth() / NumberOfSlice) * (index - 1)) : 0))
.attr("width", (d) => xScale(d['ValueItem' + index]))
.attr("height", (yScale.bandwidth() / NumberOfSlice) - 2)
.attr('fill', color(index - 1))
.on('mousedown', OnMouseBarChartClicked)
if (ShowLabels) {
let gBarChartLabel = svgBar.append("g")
.attr('class', 'gBarChartLabel' + dataLegend[index - 1])
.attr("transform", 'translate(100 , ' + (50 + (yScale.bandwidth() / 10)) + ')');
gBarChartLabel.selectAll('.' + dataLegend[index - 1])
.data(dataSet)
.enter()
.append('text')
.attr("class", d => dataLegend[index - 1] + ' label' + d.Label.replace(/\s/g, ''))
.text((d) => d['ValueItem' + index])
.attr("x", (d) => xScale(d['ValueItem' + index]) + 5)
.attr("y", (d) => yScale(d.Label) + ((yScale.bandwidth() / NumberOfSlice) / 2) - 5 + (index == prevIndex ? ((yScale.bandwidth() / NumberOfSlice) * (index - 1)) : 0))
.attr('font-size', '12')
.on('mousedown', OnMouseBarChartClicked)
}
prevIndex = index + 1;
result['gBarChartItem' + index] = gBarChart;
}
// #endregion
// #region Draw Legend
if (dataLegend != undefined) {
let gLegendBarText = svgBar.append('g')
.attr('class', 'gLegendBarText')
.attr("transform", 'translate(' + 106 + ' , ' + 80 + ')');
gLegendBarText.selectAll('.txt')
.data(dataLegend)
.enter()
.append('text')
.text((d) => d)
.attr('class', (d) => d + ' legendText')
.attr('x', (d, i) => i * 110)
.attr('y', '-20')
.attr('font-size', '12')
.on('mousedown', OnMouseLegendClick);
let gLegendBarColor = svgBar.append('g')
.attr('class', 'gLegendBarColor')
.attr("transform", 'translate(100 , ' + 76 + ')');
gLegendBarColor.selectAll('.txt')
.data(dataLegend)
.enter()
.append('circle')
.attr('class', (d) => d + ' Legend')
.attr('cx', (d, i) => i * 110)
.attr('cy', '-20')
.attr('r', '6')
.attr('fill', (d, i) => color(i))
.on('mousedown', OnMouseLegendClick);
result.gLegendBarText = gLegendBarText;
result.gLegendBarColor = gLegendBarColor;
}
// #endregion
// #region Show/Hidden Y/X Tips
if (HiddenYTips) {
d3.selectAll('.yScale .domain')
.attr('opacity', '0')
d3.selectAll('.yScale line')
.attr('opacity', '0')
}
if (HiddenXTips) {
d3.selectAll('.xScale .domain')
.attr('opacity', '0')
d3.selectAll('.xScale line')
.attr('opacity', '0')
}
// #endregion
return result;
}
// #region Event Methods
let flag = -1;
function OnMouseLegendClick(d, i) {
if (flag != i) {
d3.selectAll('.BarChat')
.attr('opacity', '0.3');
d3.selectAll('.Legend')
.attr('opacity', '0.3');
d3.selectAll('.' + d)
.attr('opacity', '1');
CLickDownLegend(d, i);
flag = i;
} else {
d3.selectAll('.BarChat')
.attr('opacity', '1');
d3.selectAll('.Legend')
.attr('opacity', '1');
ClickUpLegend(d, i);
flag = -1;
}
}
let flagBar = -1;
function OnMouseBarChartClicked(d, i) {
if (flagBar != i) {
d3.selectAll('.BarChat')
.attr('opacity', '0.3');
d3.selectAll('.' + d.Label.replace(/\s/g, ''))
.attr('opacity', '1');
d3.selectAll('.Legend')
.attr('opacity', '1');
CLickDownBarChart(d, i);
flagBar = i;
} else {
d3.selectAll('.BarChat')
.attr('opacity', '1');
ClickUpBarChart(d, i);
flagBar = -1;
}
}
function CLickDownLegend(d, i) { }
function ClickUpLegend(d, i) { }
function CLickDownBarChart(d, i) { }
function ClickUpBarChart(d, i) { }
// #endregion