Styling series¶
Without style, a serie defaults to either a black line (for line series), or round dots for a scatter serie. In most cases this behaviour is not enough, and we would like to be able to change the color, thickness, dashing/dotting, fill color, etc… of the various series that we want to display.
To this purpose, jsGraph employs the notion of style, which is nothing else than a javascript object. A style is defined by a name
and a collection of attributes
Note
There are two default styles that ship with jsGraph and that are involved in the functionning of the library:
unselected
. This is the basic style that renders the serie by default. By default, when performing API calls without setting the style, jsGraph assumes that you mean theunselected
styleselected
. The style that is displayed when a serie, or, for a scatter plot, some points of the serie, is/are selected. It inherits the styleunselected
(see below)
Style inheritance¶
jsGraph allows you to derive some styles from others.
For example, is the style unselected
and red
look like that:
// unselected
const unselected = {
line: {
width: 3,
color: 'black'
}
}
// red
const red = {
line: {
color: 'red'
}
}
and that the following API calls are used:
serie.setStyle( unselected );
serie.setStyle( red, "red", "unselected"); // <== Red style inherits from Unselected style
serie.setActiveStyle( "red" );
Then a thick red line that is 3px width will be displayed.
Warning
All styles must inherit from another one, up and until the style unselected
. If no name is provided as the third parameter of the setStyle
API call, unselected
is assumed to be the base style.
Runtime inheritance¶
Styles are computed at runtime. In other words, taking the example that is discussed above, if the unselected
style is changed using an API call:
serie.setLineStyle( "4,4", "unselected" ); // <== Second parameter is optional here, because it defaults to "unselected"
graph.draw();
The serie with the style red
will automatically determine that it should be dashed, because it inherits from the style unselected
, which we just said should be dashed.
const graph = new Graph("example-1");
graph.resize(400, 300);
let x = [1, 2, 3, 4];
let y = [1, 2, 1, 2];
let w = Graph.newWaveform().setData(y, x);
let s = graph.newSerie('s').setWaveform(w).autoAxis();
const unselected = {
line: {
width: 3,
}
}
const red = {
line: {
color: 'red'
}
};
s.setStyle(unselected);
s.setStyle(red, "red", "unselected");
s.activateStyle("red");
graph.draw(); // You won't see this, but at this stage, the serie is not dashed
s.setLineStyle("4,4", "unselected");
graph.draw(); // Now it will be dashed
This code would display the following graph:
Object mutation¶
jsGraph allows you to mutate the style objects, but it asks that you warn him that the style has changed. This is done for optimisations purposes: the style is not recomputed, nor applied, if it hasn’t changed. Because we don’t want to start observing your objects, we just ask that you notify the serie of the change:
let coloredStyle = { };
s.setStyle( coloredStyle, "colored" );
// Later
coloredStyle.color = 'green';
s.styleHasChanged( "colored" );
Even if you change a base style that your derived style might be using, that’s fine, jsGraph will look at whether any ancestor has been modified and if so, recalculate the whole derived style.
Activating a style¶
To activate a style, use the activateStyle
with the name of style you want to apply. jsGraph does not redraw by default, for optimisation purposes. You need to call graph.draw()
afterwards.
s.activateStyle("selected");
// or:
s.setActivateStyle("selected");
// Finally, when you're ready to render:
g.draw();
Line series¶
For line series, three styles are available:
The color
The width
The dashing
They are available through individual API calls or via the setStyle
method.
API calls¶
You may use the following method signatures to set the style of the line serie:
// Sets the line width
s.setLineWidth( widthInPx, styleName = "unselected" );
// Sets the line color
s.setLineColor( '#FF0000', styleName = "unselected" );
s.setLineColor( 'red' /*, styleName... */ ); // Or use a name
s.setLineColor( 'rgba(1.0, 0.0, 0.0, 1.0)' /*, styleName... */ );
// Set the line dashing
s.setLineStyle( 1, styleName="unselected" ); // Sets mode 1. See below
s.setLineStyle( "4,4" /*, styleName... */) // Directly sets the stroke-dasharray SVG property
There are 12 different modes, for you to use with a counter for example.
1
: Straight line2
: 1px dots spaced by 1px3
: 2px lines spaced by 2px4
: 3px lines spaced by 3px5
: 4px lines spaced by 4px6
: 5px lines spaced by 5px7
: Long dashes, short gaps8
: Short dashes, large gaps9
: Long dashes, alternating short and long gaps10
: Alternating dashed and dots11
: Very long dashes, short gaps12
: Short dashes, very long gaps
setStyle method¶
Use the setStyle method to set all three parameters at once. Consider the following snippet:
let style = {
line: {
color: 'red',
width: 4,
style: 2
}
};
s.setStyle( style, "myStyleName", "unselected" ); // <== Inherits from the unselected style, but that parameter is optional
Scatter series¶
Scatter series offer a lot of styling possibilities. You affect the shape, size and appearence of a “marker”, which is the element that is displayed at each point of the serie. What’s interesting is that all markers of a serie need not be the same ones. We offer a lot of possibilities to apply modifications.
Basic styling¶
You may use a javascript object that will directly be mapped to the SVG properties of the object:
let style = {
shape: 'circle',
cx: 0,
cy: 0,
r: 3,
stroke: 'transparent',
fill: 'black'
}
Will create the following SVG element
<circle cx="0" cy="0" r="3" stroke="transparent" fill="black" />
You can therefore use any SVG element available to you.
The only reserved key in the object is shape
, which of course is transformed into the SVG node name.
Setting the style¶
For scatter series, use the setMarkerStyle
or setStyle
method, with slightly more complex parameters:
let style = {
shape: 'circle',
cx: 0,
cy: 0,
r: 3,
stroke: 'transparent',
fill: 'black'
}
// Basic version
s.setMarkerStyle(style, "styleName", "inheritedStyleName" ); // <== Second and third parameters default to "unselected"
// With modifiers (see below)
s.setMarkerStyle(style, arrayOrFuncOfModifiers, "styleName", "inheritedStyleName" ); // <== Third and fourth parameters default to "unselected"
// Generic setStyle method
let gStyle = {
markers: {
all: style,
modifiers: arrayOrFuncOfModifiers
}
};
s.setStyle( gStyle, "styleName", "inheritedStyleName" ); <== Again, second and third parameters default to "unselected"
Modifiers¶
Maybe you want to draw attention to a specific marker. In that case, you can use the modifiers to set its properties. You have two possibilities:
You may either feed an array of any length, but where the index of the point you want to modify contains a javascript that will extend the style at that position:
let modifiers = Array( n ); modifiers[ 258 ] = { fill: 'blue' }; // <== Fills the point number 258 with the color blue
Use a runtime method to determine the modifier on the fly (Be careful when using time sensitive applications)
let modifiers = ( x, y, index ) => { return y > 0 ? { fill: 'green' } : { fill: 'red' } };
The following shows an example of using the style and modifiers:
const graph = new Graph("example-2");
graph.resize(400, 300);
let x = new Array(200).fill(0).map((x, index) => index / 20);
let y = [...x].map(x => Math.sin(x));
let w = Graph.newWaveform().setData(y, x);
let s = graph.newSerie('s', {}, 'scatter').setWaveform(w).autoAxis();
const posModifier = { fill: 'green' };
const negModifier = { fill: 'red' };
const posNegStyle = {
markers: {
all: {
shape: 'rect',
width: 4,
height: 2,
x: -2,
y: -1
},
modifiers: (x, y, index) => {
return index % 5 != 0 ? false : (y < 0 ? negModifier : posModifier) // Display every 5 marker
}
}
};
s.setStyle(posNegStyle, "posNeg");
s.activateStyle("posNeg");
graph.draw();
This code would display the following graph:
Note
When using a modifier method, return false
to deactivate the marker rendering at that particular index.
Individual styles names¶
Modifiers work great if you want to highlight some of the markers using a special style. However, you can also assign style names to each point independently. For example, taking the example above (and adding some animation onto it), we could define two styles:
let neg = { shape: 'circle', r: 3, fill: 'red' }
let pos = { shape: 'rect', width: 4, height: 4, x: -2, y: -2, fill: 'green' };
s.setMarkerStyle(neg, "negative");
s.setMarkerStyle(pos, "positive");
s.setIndividualStyleNames((s, i) => s.getWaveform().getY(i) > 0 ? 'positive' : 'negative');
This would output the following graph
Enabling markers with line series¶
Line series extend from scatter series, but have markers by default disabled. If you want to use markers with a line serie, use
s.setMarkers( true ); // First parameter defaults to true, so s.setMarkers(); also enable markers
Closing example¶
Obviously, we can start mixing things up and have a little bit of fun:
const graph = new Graph("example-4");
graph.resize(400, 300);
let date = Date.now();
let s = graph.newSerie('s', {}, 'line').autoAxis();
function d() {
let phase = (Date.now() - date) / 1000;
let x = new Array(200);
x = x.fill(0).map((x, index) => index / 10);
let y = [...x].map(x => Math.sin(x + phase));
let w = Graph.newWaveform();
w.setData(y, x);
s.setWaveform(w);
s.setIndividualStyleNames((s, i) => s.getWaveform().getY(i) > Math.cos(phase) ? 'positive' : 'negative');
graph.draw();
}
let def = { line: { color: 'orange', width: 2 } };
let neg = { markers: { all: { shape: 'circle', r: 3, fill: 'red' } } }
let pos = { markers: { all: { fill: 'green' }, modifiers: (x, y, index) => index % 2 == 0 ? { fill: 'blue' } : null } };
s.setMarkers();
s.setStyle(def, "unselected"); // In the scatter serie, this is overridden by setIndividualStyleNames, but the line serie will take the "unselected" style
s.setStyle(neg, "negative");
s.setStyle(pos, "positive", "negative");
graph.draw();
setInterval(d, 100);
That’s all we got (for now) !