<!DOCTYPE html>
|
<html>
|
<head>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<title>The source code</title>
|
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
|
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
|
<style type="text/css">
|
.highlight { display: block; background-color: #ddd; }
|
</style>
|
<script type="text/javascript">
|
function highlight() {
|
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
|
}
|
</script>
|
</head>
|
<body onload="prettyPrint(); highlight();">
|
<pre class="prettyprint lang-js"><span id='Ext-chart-series-Radar'>/**
|
</span> * @class Ext.chart.series.Radar
|
*
|
* Creates a Radar Chart. A Radar Chart is a useful visualization technique for comparing different quantitative values for
|
* a constrained number of categories.
|
*
|
* As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart
|
* documentation for more information. A typical configuration object for the radar series could be:
|
*
|
* @example
|
* var store = Ext.create('Ext.data.JsonStore', {
|
* fields: ['name', 'data1', 'data2', 'data3'],
|
* data: [
|
* { 'name': 'metric one', 'data1': 14, 'data2': 12, 'data3': 13 },
|
* { 'name': 'metric two', 'data1': 16, 'data2': 8, 'data3': 3 },
|
* { 'name': 'metric three', 'data1': 14, 'data2': 2, 'data3': 7 },
|
* { 'name': 'metric four', 'data1': 6, 'data2': 14, 'data3': 23 },
|
* { 'name': 'metric five', 'data1': 36, 'data2': 38, 'data3': 33 }
|
* ]
|
* });
|
*
|
* Ext.create('Ext.chart.Chart', {
|
* renderTo: Ext.getBody(),
|
* width: 500,
|
* height: 300,
|
* animate: true,
|
* theme:'Category2',
|
* store: store,
|
* axes: [{
|
* type: 'Radial',
|
* position: 'radial',
|
* label: {
|
* display: true
|
* }
|
* }],
|
* series: [{
|
* type: 'radar',
|
* xField: 'name',
|
* yField: 'data1',
|
* showInLegend: true,
|
* showMarkers: true,
|
* markerConfig: {
|
* radius: 5,
|
* size: 5
|
* },
|
* style: {
|
* 'stroke-width': 2,
|
* fill: 'none'
|
* }
|
* },{
|
* type: 'radar',
|
* xField: 'name',
|
* yField: 'data2',
|
* showMarkers: true,
|
* showInLegend: true,
|
* markerConfig: {
|
* radius: 5,
|
* size: 5
|
* },
|
* style: {
|
* 'stroke-width': 2,
|
* fill: 'none'
|
* }
|
* },{
|
* type: 'radar',
|
* xField: 'name',
|
* yField: 'data3',
|
* showMarkers: true,
|
* showInLegend: true,
|
* markerConfig: {
|
* radius: 5,
|
* size: 5
|
* },
|
* style: {
|
* 'stroke-width': 2,
|
* fill: 'none'
|
* }
|
* }]
|
* });
|
*
|
* In this configuration we add three series to the chart. Each of these series is bound to the same
|
* categories field, `name` but bound to different properties for each category, `data1`, `data2` and
|
* `data3` respectively. All series display markers by having `showMarkers` enabled. The configuration
|
* for the markers of each series can be set by adding properties onto the markerConfig object.
|
* Finally we override some theme styling properties by adding properties to the `style` object.
|
*/
|
Ext.define('Ext.chart.series.Radar', {
|
|
/* Begin Definitions */
|
|
extend: 'Ext.chart.series.Series',
|
|
requires: ['Ext.chart.Shape', 'Ext.fx.Anim'],
|
|
<span id='Ext-chart-series-Radar-cfg-type'> /* End Definitions */
|
</span>
|
type: "radar",
|
alias: 'series.radar',
|
|
|
<span id='Ext-chart-series-Radar-property-rad'> rad: Math.PI / 180,
|
</span>
|
<span id='Ext-chart-series-Radar-cfg-showInLegend'> showInLegend: false,
|
</span>
|
<span id='Ext-chart-series-Radar-cfg-style'> /**
|
</span> * @cfg {Object} style
|
* An object containing styles for overriding series styles from Theming.
|
*/
|
style: {},
|
|
<span id='Ext-chart-series-Radar-cfg-xField'> /**
|
</span> * @cfg {String} xField
|
* The name of the data Model field corresponding to the x-axis (angle) value.
|
*/
|
|
<span id='Ext-chart-series-Radar-cfg-yField'> /**
|
</span> * @cfg {String} yField
|
* The name of the data Model field corresponding to the y-axis (radius) value.
|
*/
|
|
<span id='Ext-chart-series-Radar-cfg-showMarkers'> /**
|
</span> * @cfg {Boolean} showMarkers
|
* Whether markers should be displayed at the data points of the series. If true,
|
* then the {@link #markerConfig} config item will determine the markers' styling.
|
*/
|
|
<span id='Ext-chart-series-Radar-cfg-markerConfig'> /**
|
</span> * @cfg {Object} markerConfig
|
* The display style for the markers. Only used if {@link #showMarkers} is true.
|
* The markerConfig is a configuration object containing the same set of properties defined in
|
* the Sprite class. For example, if we were to set red circles as markers to the series we could
|
* pass the object:
|
*
|
* @example
|
* markerConfig: {
|
* type: 'circle',
|
* radius: 4,
|
* 'fill': '#f00'
|
* }
|
*/
|
|
constructor: function(config) {
|
this.callParent(arguments);
|
var me = this,
|
surface = me.chart.surface;
|
me.group = surface.getGroup(me.seriesId);
|
if (me.showMarkers) {
|
me.markerGroup = surface.getGroup(me.seriesId + '-markers');
|
}
|
},
|
|
<span id='Ext-chart-series-Radar-method-drawSeries'> /**
|
</span> * Draws the series for the current chart.
|
*/
|
drawSeries: function() {
|
var me = this,
|
store = me.chart.getChartStore(),
|
data = store.data.items,
|
d, record,
|
group = me.group,
|
chart = me.chart,
|
seriesItems = chart.series.items,
|
s, sLen, series,
|
field = me.field || me.yField,
|
surface = chart.surface,
|
chartBBox = chart.chartBBox,
|
colorArrayStyle = me.colorArrayStyle,
|
centerX, centerY,
|
items,
|
radius,
|
maxValue = 0,
|
fields = [],
|
max = Math.max,
|
cos = Math.cos,
|
sin = Math.sin,
|
pi2 = Math.PI * 2,
|
l = store.getCount(),
|
startPath, path, x, y, rho,
|
i, nfields,
|
seriesStyle = me.seriesStyle,
|
axis = chart.axes && chart.axes.get(0),
|
aggregate = !(axis && axis.maximum);
|
|
me.setBBox();
|
|
maxValue = aggregate? 0 : (axis.maximum || 0);
|
|
Ext.apply(seriesStyle, me.style || {});
|
|
//if the store is empty then there's nothing to draw
|
if (!store || !store.getCount() || me.seriesIsHidden) {
|
me.hide();
|
me.items = [];
|
if (me.radar) {
|
me.radar.hide(true);
|
}
|
me.radar = null;
|
return;
|
}
|
|
if(!seriesStyle['stroke']){
|
seriesStyle['stroke'] = colorArrayStyle[me.themeIdx % colorArrayStyle.length];
|
}
|
|
me.unHighlightItem();
|
me.cleanHighlights();
|
|
centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
|
centerY = me.centerY = chartBBox.y + (chartBBox.height / 2);
|
me.radius = radius = Math.min(chartBBox.width, chartBBox.height) /2;
|
me.items = items = [];
|
|
if (aggregate) {
|
//get all renderer fields
|
for (s = 0, sLen = seriesItems.length; s < sLen; s++) {
|
series = seriesItems[s];
|
fields.push(series.yField);
|
}
|
//get maxValue to interpolate
|
for (d = 0; d < l; d++) {
|
record = data[d];
|
for (i = 0, nfields = fields.length; i < nfields; i++) {
|
maxValue = max(+record.get(fields[i]), maxValue);
|
}
|
}
|
}
|
//ensure non-zero value.
|
maxValue = maxValue || 1;
|
//create path and items
|
startPath = []; path = [];
|
for (i = 0; i < l; i++) {
|
record = data[i];
|
rho = radius * record.get(field) / maxValue;
|
x = rho * cos(i / l * pi2);
|
y = rho * sin(i / l * pi2);
|
if (i == 0) {
|
path.push('M', x + centerX, y + centerY);
|
startPath.push('M', 0.01 * x + centerX, 0.01 * y + centerY);
|
} else {
|
path.push('L', x + centerX, y + centerY);
|
startPath.push('L', 0.01 * x + centerX, 0.01 * y + centerY);
|
}
|
items.push({
|
sprite: false, //TODO(nico): add markers
|
point: [centerX + x, centerY + y],
|
storeItem: record,
|
series: me
|
});
|
}
|
path.push('Z');
|
//create path sprite
|
if (!me.radar) {
|
me.radar = surface.add(Ext.apply({
|
type: 'path',
|
group: group,
|
path: startPath
|
}, seriesStyle || {}));
|
}
|
//reset on resizing
|
if (chart.resizing) {
|
me.radar.setAttributes({
|
path: startPath
|
}, true);
|
}
|
//render/animate
|
if (chart.animate) {
|
me.onAnimate(me.radar, {
|
to: Ext.apply({
|
path: path
|
}, seriesStyle || {})
|
});
|
} else {
|
me.radar.setAttributes(Ext.apply({
|
path: path
|
}, seriesStyle || {}), true);
|
}
|
//render markers, labels and callouts
|
if (me.showMarkers) {
|
me.drawMarkers();
|
}
|
me.renderLabels();
|
me.renderCallouts();
|
},
|
|
<span id='Ext-chart-series-Radar-method-drawMarkers'> // @private draws the markers for the lines (if any).
|
</span> drawMarkers: function() {
|
var me = this,
|
chart = me.chart,
|
surface = chart.surface,
|
store = chart.getChartStore(),
|
markerStyle = Ext.apply({}, me.markerStyle || {}),
|
endMarkerStyle = Ext.apply(markerStyle, me.markerConfig, {
|
fill: me.colorArrayStyle[me.themeIdx % me.colorArrayStyle.length]
|
}),
|
items = me.items,
|
type = endMarkerStyle.type,
|
markerGroup = me.markerGroup,
|
centerX = me.centerX,
|
centerY = me.centerY,
|
item, i, l, marker, rendererAttributes;
|
|
delete endMarkerStyle.type;
|
|
for (i = 0, l = items.length; i < l; i++) {
|
item = items[i];
|
marker = markerGroup.getAt(i);
|
if (!marker) {
|
marker = Ext.chart.Shape[type](surface, Ext.apply({
|
group: markerGroup,
|
x: 0,
|
y: 0,
|
translate: {
|
x: centerX,
|
y: centerY
|
}
|
}, endMarkerStyle));
|
}
|
else {
|
marker.show();
|
}
|
|
item.sprite = marker;
|
|
if (chart.resizing) {
|
marker.setAttributes({
|
x: 0,
|
y: 0,
|
translate: {
|
x: centerX,
|
y: centerY
|
}
|
}, true);
|
}
|
marker._to = {
|
translate: {
|
x: item.point[0],
|
y: item.point[1]
|
}
|
};
|
//render/animate
|
rendererAttributes = me.renderer(marker, store.getAt(i), marker._to, i, store);
|
rendererAttributes = Ext.applyIf(rendererAttributes || {}, endMarkerStyle || {});
|
if (chart.animate) {
|
me.onAnimate(marker, {
|
to: rendererAttributes
|
});
|
}
|
else {
|
marker.setAttributes(rendererAttributes, true);
|
}
|
}
|
},
|
|
<span id='Ext-chart-series-Radar-method-isItemInPoint'> isItemInPoint: function(x, y, item) {
|
</span> var point,
|
tolerance = 10,
|
abs = Math.abs;
|
point = item.point;
|
return (abs(point[0] - x) <= tolerance &&
|
abs(point[1] - y) <= tolerance);
|
},
|
|
<span id='Ext-chart-series-Radar-method-onCreateLabel'> // @private callback for when creating a label sprite.
|
</span> onCreateLabel: function(storeItem, item, i, display) {
|
var me = this,
|
group = me.labelsGroup,
|
config = me.label,
|
centerX = me.centerX,
|
centerY = me.centerY,
|
endLabelStyle = Ext.apply({}, config, me.seriesLabelStyle || {});
|
|
return me.chart.surface.add(Ext.apply({
|
'type': 'text',
|
'text-anchor': 'middle',
|
'group': group,
|
'x': centerX,
|
'y': centerY
|
}, endLabelStyle || {}));
|
},
|
|
<span id='Ext-chart-series-Radar-method-onPlaceLabel'> // @private callback for when placing a label sprite.
|
</span> onPlaceLabel: function(label, storeItem, item, i, display, animate, index) {
|
var me = this,
|
chart = me.chart,
|
resizing = chart.resizing,
|
config = me.label,
|
format = config.renderer,
|
field = config.field,
|
centerX = me.centerX,
|
centerY = me.centerY,
|
opt = {
|
x: Number(item.point[0]),
|
y: Number(item.point[1])
|
},
|
x = opt.x - centerX,
|
y = opt.y - centerY,
|
theta = Math.atan2(y, x || 1),
|
deg = theta * 180 / Math.PI,
|
labelBox, direction;
|
|
function fixAngle(a) {
|
if (a < 0) {
|
a += 360;
|
}
|
return a % 360;
|
}
|
|
label.setAttributes({
|
text: format(storeItem.get(field), label, storeItem, item, i, display, animate, index),
|
hidden: true
|
},
|
true);
|
|
// Move the label by half its height or width depending on
|
// the angle so the label doesn't overlap the graph.
|
labelBox = label.getBBox();
|
deg = fixAngle(deg);
|
if ((deg > 45 && deg < 135) || (deg > 225 && deg < 315)) {
|
direction = (deg > 45 && deg < 135 ? 1 : -1);
|
opt.y += direction * labelBox.height/2;
|
} else {
|
direction = (deg >= 135 && deg <= 225 ? -1 : 1);
|
opt.x += direction * labelBox.width/2;
|
}
|
|
if (resizing) {
|
label.setAttributes({
|
x: centerX,
|
y: centerY
|
}, true);
|
}
|
|
if (animate) {
|
label.show(true);
|
me.onAnimate(label, {
|
to: opt
|
});
|
} else {
|
label.setAttributes(opt, true);
|
label.show(true);
|
}
|
},
|
|
<span id='Ext-chart-series-Radar-method-toggleAll'> // @private for toggling (show/hide) series.
|
</span> toggleAll: function(show) {
|
var me = this,
|
i, ln, shadow, shadows;
|
if (!show) {
|
Ext.chart.series.Radar.superclass.hideAll.call(me);
|
}
|
else {
|
Ext.chart.series.Radar.superclass.showAll.call(me);
|
}
|
if (me.radar) {
|
me.radar.setAttributes({
|
hidden: !show
|
}, true);
|
//hide shadows too
|
if (me.radar.shadows) {
|
for (i = 0, shadows = me.radar.shadows, ln = shadows.length; i < ln; i++) {
|
shadow = shadows[i];
|
shadow.setAttributes({
|
hidden: !show
|
}, true);
|
}
|
}
|
}
|
},
|
|
<span id='Ext-chart-series-Radar-method-hideAll'> // @private hide all elements in the series.
|
</span> hideAll: function() {
|
this.toggleAll(false);
|
this.hideMarkers(0);
|
},
|
|
<span id='Ext-chart-series-Radar-method-showAll'> // @private show all elements in the series.
|
</span> showAll: function() {
|
this.toggleAll(true);
|
},
|
|
<span id='Ext-chart-series-Radar-method-hideMarkers'> // @private hide all markers that belong to `markerGroup`
|
</span> hideMarkers: function(index) {
|
var me = this,
|
count = me.markerGroup && me.markerGroup.getCount() || 0,
|
i = index || 0;
|
for (; i < count; i++) {
|
me.markerGroup.getAt(i).hide(true);
|
}
|
},
|
|
<span id='Ext-chart-series-Radar-method-getAxesForXAndYFields'> // @private return the radial axis as yAxis (there is no xAxis).
|
</span> // Required by the base class 'Ext.chart.axis.Axis'.
|
getAxesForXAndYFields: function() {
|
var me = this,
|
chart = me.chart,
|
axes = chart.axes,
|
axis = [].concat(axes && axes.get(0));
|
|
return {
|
yAxis: axis
|
};
|
}
|
});
|
|
</pre>
|
</body>
|
</html>
|