Skip to content
This repository has been archived by the owner on Nov 4, 2022. It is now read-only.

Vanilla radar - initial commit #42

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
885ef94
drawing basics of radar chart
Feb 7, 2017
103844e
drawing axis, shapes, and rings
Feb 9, 2017
eac5448
added draw function
Feb 9, 2017
a07826c
adding labels
Feb 9, 2017
179346e
added label wrapping
Feb 10, 2017
75e0d89
Merge branch 'master' of https://github.com/IBM-Design/charts
Feb 10, 2017
fb70542
removing linting errors
Feb 21, 2017
59c749a
more linting errors fixed
Feb 21, 2017
7f47a08
updated data and more lint errors
Feb 21, 2017
ad971e1
drawing basics of radar chart
Feb 7, 2017
df09e47
drawing axis, shapes, and rings
Feb 9, 2017
e17aa16
added draw function
Feb 9, 2017
7ea6772
adding labels
Feb 9, 2017
fa040b7
added label wrapping
Feb 10, 2017
de21e2d
removing linting errors
Feb 21, 2017
d22bbd1
more linting errors fixed
Feb 21, 2017
9bf2dfa
updated data and more lint errors
Feb 21, 2017
673a87c
updated to use commonjs
photodow Feb 22, 2017
25e5c75
replaced with the client side build
photodow Feb 22, 2017
747cce4
moved the juice of everything to the root of /src
photodow Feb 22, 2017
afe3ef4
simplified the code to compile and run dev
photodow Feb 22, 2017
a719124
updated to reflect changes to /lib
photodow Feb 22, 2017
c5f0378
updated the readme.md to better reflect how to develop within this pa…
photodow Feb 22, 2017
e665b24
fixed linting errors
photodow Feb 22, 2017
9e2a642
various small little changes
photodow Feb 22, 2017
388c663
fixed conflicts
photodow Feb 22, 2017
20624a4
Merge branch 'master' of https://github.com/IBM-Design/charts
Feb 22, 2017
df9e0b3
removing linting errors
Feb 21, 2017
25024b5
more linting errors fixed
Feb 21, 2017
d4ae651
updated data and more lint errors
Feb 21, 2017
5af23f1
Merge branch 'vanilla-radar' of https://github.com/ninth-mind/charts …
Feb 22, 2017
b141f03
Merge pull request #1 from photodow/vanilla-radar
chalupagrande Feb 22, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/charts-vanilla-radar/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Copyright 2017 IBM
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
21 changes: 21 additions & 0 deletions packages/charts-vanilla-radar/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# `@ibm-design/charts-vanilla-radar`

## Usage

#### Install
```bash
# you can use yarn
yarn add @ibm-design/charts-vanilla-radar

# or npm to add it to your project
npm install @ibm-design/charts-vanilla-radar
```

## Development

#### Start dev environment
```bash
npm start
```

Then go to http://localhost:8082/ to see this package rendered.
15 changes: 15 additions & 0 deletions packages/charts-vanilla-radar/gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const gulp = require('gulp');
const sass = require('gulp-sass');
const plumber = require('gulp-plumber');
const sourcemaps = require('gulp-sourcemaps');

gulp.task('compile-scss', () => {
return gulp.src('src/styles/*.scss')
.pipe(plumber())
.pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(sourcemaps.write('maps'))
.pipe(gulp.dest('lib'));
});

gulp.task('default', ['compile-scss']);
12 changes: 12 additions & 0 deletions packages/charts-vanilla-radar/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vanilla Radar Chart</title>
<link rel="stylesheet" href="lib/styles.css">
</head>
<body>
<svg class="radar"></svg>
<script src="lib/index.js"></script>
</body>
</html>
27 changes: 27 additions & 0 deletions packages/charts-vanilla-radar/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@ibm-design/charts-vanilla-radar",
"version": "0.0.0",
"main": "src/index.js",
"scripts": {
"build": "npm run clean && webpack && gulp",
"start": "npm run build && webpack-dev-server --progress --colors",
"clean": "rimraf lib"
},
"license": "Apache-2.0",
"devDependencies": {
"gulp": "^3.9.1",
"gulp-plumber": "^1.1.0",
"gulp-sass": "^3.1.0",
"gulp-sourcemaps": "^2.4.1",
"rimraf": "^2.5.4",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.4.1"
},
"dependencies": {
"d3-array": "^1.0.2",
"d3-scale": "^1.0.4",
"d3-selection": "^1.0.3",
"d3-selection-multi": "^1.0.1",
"d3-shape": "^1.0.4"
}
}
7 changes: 7 additions & 0 deletions packages/charts-vanilla-radar/src/__tests__/Chart-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// import Chart from '../';

describe('Radar Component', () => {
it('should render', () => {
expect(true).toBe(true, 'This is a placeholder true');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine we should probably add tests for these? @seejamescode

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes please 😄

});
});
241 changes: 241 additions & 0 deletions packages/charts-vanilla-radar/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
import { selection, select } from 'd3-selection';
import { scaleOrdinal, scaleLinear } from 'd3-scale';
import { max, merge, range } from 'd3-array';
import { radialLine } from 'd3-shape';
import 'd3-selection-multi';

export { selection }; // XXX

export default class Radar {

constructor(graphNode, data, opts) {
this.data = this.formatData(data);
this.target = select(graphNode);

this.scale;
this.line;
this.color = scaleOrdinal()
.range(opts.colors);
this.axis = {};

this.cfg = (() => {
const w = opts.size || 500;
const h = w;
const numAxis = this.data[0].length;
const margin = opts.margins;
const r = w / 2 - max([margin.top + margin.bottom, margin.right + margin.left]);

return {
w: w,
h: h,
r: r,
margin: margin,
units: opts.units,
levels: opts.levels,
max: null, // will be determined by data
labelFactor: opts.labelFactor, // how much further outside the radius does the label appears
wrapWidth: opts.wrapWidth || 60, // word wrap after this number of pixels
opacityArea: opts.opacityArea,
strokeWidth: 2,
numAxis: numAxis,
angleSlice: Math.PI * 2 / numAxis, // angle of slice in radians
shape: opts.shape || 'circle', //circle, polygon, square,
dotSize: 4, //if not set, dots will not be drawn.
axisStyle: {
'stroke': 'black',
'stroke-width': 1,
},
};
})();
} // constructor


draw() {

//setup
this.scalesAndLinesFunctions();
this.wrapper = this.setupRadar();

const blobs = this.wrapper.append('g').attr('class', 'blobs'); //draw blobs & dots

for (let i = 0; i < this.data.length; i++) {
const g = blobs.append('g').attr('class', 'blob-' + i); //blob

g.append('path').datum(this.data[i]).attrs({
'stroke-width': 1.5,
'd' : this.line,
'fill': () => { return this.color(i); },
});

//dots
g.selectAll('.dot').data(this.data[i]).enter().append('circle').attrs({
'stroke-width': 1.5,
'cx': (d, i) => { return this.scale( d.value) * Math.sin(this.cfg.angleSlice * i + Math.PI / 2);},
'cy': (d, i) => { return this.scale( d.value) * Math.cos(this.cfg.angleSlice * i + Math.PI / 2);},
'r': this.cfg.dotSize,
'fill': () => { return this.color(i);},
'opacity': 0.4,
'class': 'dot',
});
}
}//draw

scalesAndLinesFunctions() {
const that = this;

this.cfg.max = max(merge(this.data), d => d.value);
this.scale = scaleLinear()
.domain([0, this.cfg.max])
.range([0, this.cfg.r]);

this.line = radialLine()
.angle((d, i) => { return -(i * that.cfg.angleSlice) + Math.PI / 2;})
.radius((d) => { return that.scale(d.value);});

}//scalesAndLinesFunctions

setupRadar() {
this.target.styles({
width: this.cfg.w,
height: this.cfg.h,
});

const globalGroup = this.target.append('g').attrs({
'class': 'chart',
'transform': `translate(${this.cfg.w / 2} ${this.cfg.h / 2})`,
});

this.axis.names = this.data[0].map( el => el.axis);
this.axis.length = this.axis.names.length;

//puts 0,0 in the center of the svg

// draws the axis
if (this.cfg.axisStyle) {
this.axisGroup = globalGroup.append('g').attr('class', 'axis-lines');
this.axisGroup.selectAll('.axis-line').data(this.axis.names).enter().append('line')
.attrs({
'x1': 0,
'y1': 0,
// `+ Math.PI/2 to make the Axis line up with the correct Data`
'x2': (d, i) => {
return this.scale(this.cfg.max * 1.05) * Math.sin( this.cfg.angleSlice * i + Math.PI / 2);
},
'y2': (d, i) => {
return this.scale(this.cfg.max * 1.05) * Math.cos( this.cfg.angleSlice * i + Math.PI / 2);
},
'opacity': 0.3,
'class': 'axis-line',
}).styles(this.cfg.axisStyle);
}

if (this.cfg.shape == 'circle') {
//draw rings
const ringInterval = this.cfg.max / this.cfg.levels;
//add 1 so you include the MAX
const ringRadiusValues = range(ringInterval, this.cfg.max + 1, ringInterval).reverse();

let g = globalGroup.append('g').attr('class', 'grid-circle');
g.append('g').attr('class', 'rings')
.selectAll('.ring').data(ringRadiusValues)
.enter().append('circle').attrs({
'fill': 'none',
'cx': 0,
'cy': 0,
'r': (d) => { return this.scale(d); },
'stroke': 'black',
'stroke-width': 1,
'stroke-dasharray': '5 5',
'opacity': 0.2,
'class': 'ring',
});

//add the unit labels on the rings
g.append('g').attr('class', 'rings-labels')
.selectAll('.ring-label').data(ringRadiusValues)
.enter().append('text').attrs({
'class': 'ring-label',
'x': '0',
'y': (d) => {return -this.scale(d);},
'dy': '-0.3em',
'dx': '0.5em',
'font-size': '0.8em',
'fill': 'grey',
'opacity': 0.4,
})
.text((d) => {return d + this.cfg.units;});
g.append('g').attr('class', 'legend')
.selectAll('.axis-label').data(this.data[0]).enter().append('text').attrs({
'class': 'axis-label',
'x': (d, i) => {
return (this.scale(this.cfg.max) * 1.05 + this.cfg.labelFactor ) *
Math.sin(this.cfg.angleSlice * i + Math.PI / 2);
},
'y': (d, i) => {
return (this.scale(this.cfg.max) * 1.05 + this.cfg.labelFactor ) *
Math.cos(this.cfg.angleSlice * i + Math.PI / 2);
},
'font-size': '0.8em',
'fill': 'grey',
'opacity': 0.4,
'text-anchor': 'middle',
})
.text((d) => {return d.axis;})
.call(this.wrap, this.cfg.wrapWidth);




} else if (this.cfg.shape == 'polygon') {
//TODO
Copy link
Collaborator

@photodow photodow Feb 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to write a user story around this polygon shape.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still want me to merge it now?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seejamescode if you've looked at the code, and are happy with it then it should be merged. I created stories for these to do's, and we can tackle them after this pull request goes in.

} else if (this.cfg.shape == 'square') {
//TODO
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to write a user story around this square shape.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
return globalGroup;
}//setupRadar

//customize this function to fit data model you want
formatData(data) {
data.map(d => {
d.map(v => {
v.value = Math.round(v.value * 100);
});
});

return data;
} // formatData


//Adapted from http://bl.ocks.org/mbostock/7555321
//Wraps SVG text
wrap(text, width) {
text.each(function() {
const text = select(this);
const words = text.text().split(/\s+/).reverse();
const lineHeight = 1.4; // ems
const y = text.attr('y');
const x = text.attr('x');
const dy = parseFloat(text.attr('dy')) || 0;

let word;
let line = [];
let lineNumber = 0;
let tspan = text.text(null).append('tspan').attr('x', x).attr('y', y).attr('dy', dy + 'em');

while (word = words.pop()) {
line.push(word);
tspan.text(line.join(' '));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(' '));
line = [word];
tspan = text.append('tspan')
.attr('x', x)
.attr('y', y)
.attr('dy', ++lineNumber * lineHeight + dy + 'em')
.text(word);
}
}
});
}//wrap
}
32 changes: 32 additions & 0 deletions packages/charts-vanilla-radar/src/scripts/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export default [
[//iPhone
{axis:'Apdex', value:0.80},
{axis:'Alerts', value:0.66},
{axis:'Request Volume', value:0.35},
{axis:'Memory', value:0.54},
{axis:'CPU', value:0.38},
{axis:'Disk', value:0.23},
{axis:'Network', value:0.23},
{axis:'Heap', value:0.16},
],
[//Samsung
{axis:'Apdex', value:0.58},
{axis:'Alerts', value:0.66},
{axis:'Request Volume', value:0.35},
{axis:'Memory', value:0.23},
{axis:'CPU', value:0.36},
{axis:'Disk', value:0.13},
{axis:'Network', value:0.11},
{axis:'Heap', value:0.35},
],
[//Nokia Smartphone
{axis:'Apdex', value:0.26},
{axis:'Alerts', value:0.10},
{axis:'Request Volume', value:0.30},
{axis:'Memory', value:0.14},
{axis:'CPU', value:0.22},
{axis:'Disk', value:0.04},
{axis:'Network', value:0.23},
{axis:'Heap', value:0.41},
],
];
16 changes: 16 additions & 0 deletions packages/charts-vanilla-radar/src/scripts/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import data from './data';
import Radar from '../index';

const a = new Radar('svg', data, {
'size': 800,
'margins': {top: 70, right: 70, bottom: 70, left: 70},
'colors': ['#EDC951', '#CC333F', '#00A0B0'],
'units': '%',
'levels': 5,
'opacityArea': 0.4,
'labelFactor': 30,
'shape': 'circle',
'wrapWidth': 60,
});

a.draw();
Loading