i have been trying to make a custom BarChart in Java for a school project but for some reason it has some weird Scaling issues. Here is the Code.
static class BarChart extends JPanel
{
private int[] chartValues;
private String[] chartLabels;
private String chartTitle;
public BarChart(String title,int[] values,String[]labels)
{
this.chartTitle = title;
this.chartValues = values;
this.chartLabels = labels;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Random r = new Random();
if(this.chartValues == null || this.chartValues.length==0)
{
return;
}
Dimension chartDimension = this.getSize();
int panelWidth = chartDimension.width;
int panelHeight = chartDimension.height;
int barWidth = panelWidth / this.chartValues.length;
int maxValue = this.chartValues[0];
int minValue = this.chartValues[0];
for(int tempValue:this.chartValues)
{
maxValue = Math.max(maxValue, tempValue);
minValue = Math.min(minValue, tempValue);
}
Font titleFont = new Font("Book Antiqua", Font.BOLD, 15);
FontMetrics titleFontMetrics = g.getFontMetrics(titleFont);
Font labelFont = new Font("Book Antiqua", Font.PLAIN, 14);
FontMetrics labelFontMetrics = g.getFontMetrics(labelFont);
int titleWidth = titleFontMetrics.stringWidth(this.chartTitle);
int stringHeight = titleFontMetrics.getAscent();
int stringWidth = (panelWidth - titleWidth) / 2;
g.setFont(titleFont);
g.drawString(this.chartTitle, stringWidth, stringHeight);
int top = titleFontMetrics.getHeight();
int bottom = labelFontMetrics.getHeight();
if(maxValue==minValue)
{
return;
}
double barScale = (panelHeight - top - bottom)/(maxValue - minValue);
stringHeight = panelHeight - labelFontMetrics.getDescent();
int xPos = 5;
g.setFont(labelFont);
for(int i=0; i<this.chartValues.length;i++)
{
int tempValue = this.chartValues[i];
int barHeight = (int) ( (double)tempValue * barScale);
int yPos = top;
if(tempValue>=0)
{
yPos += (int) ((maxValue - tempValue)* barScale);
}
else
{
yPos += (int) (maxValue * barScale);
barHeight = - barHeight;
}
g.setColor(new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255)));
g.fillRect(xPos, yPos, barWidth, barHeight);
g.setColor(Color.BLUE);
g.drawRect(xPos, yPos, barWidth, barHeight);
xPos += barWidth;
}
g.setColor(Color.BLACK);
g.drawString("Xronos", stringWidth, stringHeight);
}
}
But when i run this with my main with values {1,5,4,7,120} i get this depending on the screen resolution.
Wrong image (the height between bars and label is too much).
Correct height between bars and label. I really apreciate any help. And sorry if this stupid is a question.
you are doing integer division here:
double barScale = (panelHeight - top - bottom)/(maxValue - minValue);
try
double barScale = (panelHeight - top - bottom)/(double)(maxValue - minValue);
instead
Related
I am trying to add a square to the canvas when a mouse key is pressed and i want it to remain on the canvas when the mouse key is released, but it disappears when is released the key. Can anybody help me, what am i doing wrong?
int squareSize = 6;
final float DIFF_SIZE = 1;
final int MIN_COLOUR = 1;
final int MAX_COLOUR = 10;
final float INIT_RED = 100, INIT_GREEN = 50, INIT_BLUE = 80;
final float FINAL_RED = 255, FINAL_GREEN = 200, FINAL_BLUE = 250;
final float MAX_SIZE = 40;
final float X_SPACING = 10;
final float Y_SPACING = 10;
float squareX, squareY;
void setup() {
size(600, 600);
}
void draw() {
squareX = mouseX - squareSize / 2;
squareY = mouseY - squareSize / 2;
background(255);
drawRowsOfBlocks();
}
void drawOneBlock() {
rect(squareX, squareY, squareSize, squareSize);
for (int i = MIN_COLOUR; mousePressed && i <= MAX_COLOUR / 10; i++)
{
float redValue = INIT_RED + (i - MIN_COLOUR) / (MAX_COLOUR - MIN_COLOUR)(FINAL_RED - INIT_RED);
float greenValue = INIT_GREEN + (i - MIN_COLOUR) / (MAX_COLOUR - MIN_COLOUR)(FINAL_GREEN - INIT_GREEN);
float blueValue = INIT_BLUE + (i - MIN_COLOUR) / (MAX_COLOUR - MIN_COLOUR) * (FINAL_BLUE - INIT_BLUE);
fill(redValue, greenValue, blueValue);
rect(squareX, squareY, squareSize, squareSize);
squareSize += DIFF_SIZE;
}
if (squareSize > MAX_SIZE) {
squareSize = 6;
}
}
void drawRowsOfBlocks() {
drawOneBlock();
for (int i = 1; keyPressed && i <= 2; i++) {
drawOneBlock();
float squareY2;
squareY2 = squareY + squareSize + Y_SPACING;
squareY = squareY2;
}
}
Create a class which can handle a rectangle. The calls needs a method to draw the rectangle (Draw()) and a method to update the position and size of the rectangle (Update()):
final int DIFF_SIZE = 1;
final int MIN_SIZE = 6;
final int MAX_SIZE = 40;
final float INIT_RED = 100, INIT_GREEN = 50, INIT_BLUE = 80;
final float FINAL_RED = 255, FINAL_GREEN = 200, FINAL_BLUE = 250;
class Rectangle {
int pos_x, pos_y, size;
color col;
Rectangle(int px, int py, int s, color c) {
col = c;
pos_x = px; pos_y = py;
size = s;
}
void Update(int px, int py, int inc_size) {
pos_x = px; pos_y = py;
size += inc_size;
if (size > MAX_SIZE)
size = MIN_SIZE;
float w = float(size - MIN_SIZE) / float(MAX_SIZE - MIN_SIZE);
float redValue = INIT_RED + w * (FINAL_RED - INIT_RED);
float greenValue = INIT_GREEN + w * (FINAL_GREEN - INIT_GREEN);
float blueValue = INIT_BLUE + w * (FINAL_BLUE - INIT_BLUE);
col = color(int(redValue), int(greenValue), int(blueValue));
}
void Draw() {
fill(col);
rect(pos_x-size/2, pos_y-size/2, size, size);
}
}
Use ArrayList to store all the drawn rectangles:
ArrayList<Rectangle> rectangles = new ArrayList<Rectangle>();
Add a global, boolean state (drawingRect) which indicates if the mouse button is currently pressed. Set the state and add new rectangle at the end of the list when the mousePressed() event occurs. rest the state when the mouseReleased() event occurs
boolean drawingRect = false;
void mousePressed() {
drawingRect = true;
color col = color(int(INIT_RED), int(INIT_GREEN), int(INIT_BLUE));
rectangles.add(new Rectangle(mouseX, mouseY, MIN_SIZE, col));
}
void mouseReleased() {
drawingRect = false;
}
Use the method .Update(), to change the location and size of the last rectangle in the list as long as the state drawingRect indicates that a mouse button is pressed.
Continuously draw all te rectangles in a loop:
void setup() {
size(600, 600);
}
void draw() {
if (drawingRect && rectangles.size() > 0) {
Rectangle lastRect = rectangles.get(rectangles.size()-1);
lastRect.Update(mouseX, mouseY, DIFF_SIZE);
}
background(255);
for (int i = 0; i < rectangles.size(); i++) {
Rectangle rect = rectangles.get(i);
rect.Draw();
}
}
I was using this code placed here to generate bar-charts for my datasets. However, the colours were all the same (red in the code), so I decided to generate a colour ramp for this. I wrote the following code:
Color[] getColorRamp(int numColours)
{
Color[] colours = new Color[numColours];
int red_1 = 255;
int green_1 = 0;
int blue_1 = 0;
int red_2 = 0;
int green_2 = 0;
int blue_2 = 255;
int count = 0;
for (float t=0.0f;t<1.0f;t+=1.0/(float)numColours) {
colours[count] = new Color((int)(t*red_2 + (1-t)*red_1),
(int)(t*green_2 + (1-t)*green_1),
(int)(t*blue_2 + (1-t)*blue_1),34);
//System.out.print((int)(t*red_2 + (1-t)*red_1) +",");
//System.out.print((int)(t*green_2 + (1-t)*green_1) +",");
//System.out.println((int)(t*blue_2 + (1-t)*blue_1));
}
return colours;
}
It is here, where the problem starts. Only the first colour (pretty light blue) get rendered properly. Other colours are rendered as black! You can see that I have put System.out.println to verify the colours generated (commented in the code posted here). I saw that colours were generated as perfect RGB combinations.
The modified barchart function is posted here:
void drawBarChart(Graphics g, double[] values, String[] names, String title)
{
if (values == null || values.length == 0)
return;
double minValue = 0;
double maxValue = 0;
for (int i = 0; i < values.length; i++) {
if (minValue > values[i])
minValue = values[i];
if (maxValue < values[i])
maxValue = values[i];
}
//Graphics2D g = (Graphics2D)gg;
Dimension d = getSize();
int clientWidth = d.width;
int clientHeight = d.height;
int barWidth = clientWidth / values.length;
Font titleFont = new Font("SansSerif", Font.BOLD, 20);
FontMetrics titleFontMetrics = g.getFontMetrics(titleFont);
Font labelFont = new Font("SansSerif", Font.PLAIN, 10);
FontMetrics labelFontMetrics = g.getFontMetrics(labelFont);
int titleWidth = titleFontMetrics.stringWidth(title);
int y = titleFontMetrics.getAscent();
int x = (clientWidth - titleWidth) / 2;
g.setFont(titleFont);
g.drawString(title, x, y);
int top = titleFontMetrics.getHeight();
int bottom = labelFontMetrics.getHeight();
if (maxValue == minValue)
return;
double scale = (clientHeight - top - bottom) / (maxValue - minValue);
y = clientHeight - labelFontMetrics.getDescent();
g.setFont(labelFont);
Color[] colours = getColorRamp(values.length);
for (int i = 0; i < values.length; i++) {
int valueX = i * barWidth + 1;
int valueY = top;
int height = (int) (values[i] * scale);
if (values[i] >= 0)
valueY += (int) ((maxValue - values[i]) * scale);
else {
valueY += (int) (maxValue * scale);
height = -height;
}
g.setColor(colours[i]);
g.fillRect(valueX, valueY, barWidth - 2, height);
g.setColor(Color.black);
g.drawRect(valueX, valueY, barWidth - 2, height);
int labelWidth = labelFontMetrics.stringWidth(names[i]);
x = i * barWidth + (barWidth - labelWidth) / 2;
g.drawString(names[i], x, y);
}
//paintComponent(g);
}
I wish to know, what mistake I am making!
You're probably going to hit yourself on the head now. The reason it fails is that you forget to increase the variable count after setting the first colour, so you're constantly overwriting the first element of the Color array, and leaving all the other values in the array as their initial default (null).
Fixed code:
for (float t=0.0f;t<1.0f;t+=1.0/(float)numColours) {
colours[count++] = new Color((int)(t*red_2 + (1-t)*red_1),
(int)(t*green_2 + (1-t)*green_1),
(int)(t*blue_2 + (1-t)*blue_1),34);
}
(Notice the colours[count++])
I got a below java code which plots a 2D graph where x axis has values 1,2,3,......20
and y axis has values 21,14,18..........18
The code works perfectly but the only problem is that the graph does not shows the corresponding x and y values on x axis and y axis respectively. I know it could be a small addition to the code. but i am new to java graphics and i am not able to figure out where to add the relevant code considering the time constraint.
/*Sample code */
public class GraphingData extends JPanel {
int[] data = {
21, 14, 18, 03, 86, 88, 74, 87, 54, 77,
61, 55, 48, 60, 49, 36, 38, 27, 20, 18
};
final int PAD = 20;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
// Draw ordinate.
g2.draw(new Line2D.Double(PAD, PAD, PAD, h-PAD));
// Draw abcissa.
g2.draw(new Line2D.Double(PAD, h-PAD, w-PAD, h-PAD));
// Draw labels.
Font font = g2.getFont();
FontRenderContext frc = g2.getFontRenderContext();
LineMetrics lm = font.getLineMetrics("0", frc);
float sh = lm.getAscent() + lm.getDescent();
// Ordinate label.
String s = "Average Byte Value";
float sy = PAD + ((h - 2*PAD) - s.length()*sh)/2 + lm.getAscent();
for(int i = 0; i < s.length(); i++) {
String letter = String.valueOf(s.charAt(i));
float sw = (float)font.getStringBounds(letter, frc).getWidth();
float sx = (PAD - sw)/2;
g2.drawString(letter, sx, sy);
sy += sh;
}
// Abcissa label.
s = "file blocks";
sy = h - PAD + (PAD - sh)/2 + lm.getAscent();
float sw = (float)font.getStringBounds(s, frc).getWidth();
float sx = (w - sw)/2;
g2.drawString(s, sx, sy);
// Draw lines.
double xInc = (double)(w - 2*PAD)/(data.length-1);
double scale = (double)(h - 2*PAD)/getMax();
g2.setPaint(Color.green.darker());
for(int i = 0; i < data.length-1; i++) {
double x1 = PAD + i*xInc;
double y1 = h - PAD - scale*data[i];
double x2 = PAD + (i+1)*xInc;
double y2 = h - PAD - scale*data[i+1];
g2.draw(new Line2D.Double(x1, y1, x2, y2));
}
// Mark data points.
g2.setPaint(Color.red);
for(int i = 0; i < data.length; i++) {
double x = PAD + i*xInc;
double y = h - PAD - scale*data[i];
g2.fill(new Ellipse2D.Double(x-2, y-2, 4, 4));
}
}
private int getMax() {
int max = -Integer.MAX_VALUE;
for(int i = 0; i < data.length; i++) {
if(data[i] > max)
max = data[i];
}
return max;
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new GraphingData());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
}
public void drawGrid(Graphics g)
{
g.setColor(Color.black);
int rows = model.maxy-model.miny+1;
int cols = model.maxx-model.minx+1;
int colWidth = (getWidth()-paddingFromRight - ylabelWidth)/cols;
int rowHeight = (getHeight()-xlabelHeight-headingHeight)/rows;
int endX = ylabelWidth + cols * colWidth;
int endY = headingHeight + rows*rowHeight;
for (int k = 0; k <= cols; k++)
{
g.drawLine(ylabelWidth+colWidth*k, headingHeight, ylabelWidth+colWidth*k, endY); //getHeight()-xlabelHeight
}
for (int k = 0; k <= rows;k++)
{
g.drawLine(ylabelWidth, headingHeight+rowHeight*k,endX, headingHeight+rowHeight*k);
}
}
public void drawLines(Graphics g)
{
ArrayList<Line> lines = model.getLines();
Random random = new Random(50);
for (int k = 0; k < lines.size(); k++)
{
g.setColor(new Color(255-50*k, 50*k, 2*50*k));
//g.setColor(Color.red);
drawLine(g, lines.get(k));
}
}
public void drawLine(Graphics g, Line line)
{
ArrayList<Point> points = line.points;
for (int k = 0; k<points.size()-1;k++)
{
//scale up points
Point p1 = points.get(k);
Point p2 = points.get(k+1);
g.drawLine(scaleUpX(p1.x), scaleUpY(p1.y), scaleUpX(p2.x), scaleUpY(p2.y));
g.fillOval(scaleUpX(p1.x)-5, scaleUpY(p1.y)-5, 10, 10);
}
Point p1 = points.get(points.size()-1);
g.fillOval(scaleUpX(p1.x)-5, scaleUpY(p1.y)-5, 10, 10);
}
public int scaleUpX(int x)
{
int cols = model.maxx-model.minx+1;
int colWidth = (getWidth()-paddingFromRight - ylabelWidth)/cols;
return ylabelWidth+colWidth*x;
}
public int scaleUpY(int y)
{
int rows = model.maxy-model.miny+1;
int rowHeight = (getHeight()-xlabelHeight-headingHeight)/(rows);
//int endY = getHeight()-xlabelHeight;
int endY = headingHeight+rows*rowHeight;
return endY - rowHeight*y;
}
public void drawLabels(Graphics g)
{
Dimension d = getSize();
//xlabel
g.drawString(model.xlabel, d.width/2, d.height-xlabelHeight/4);
//ylabel
g.drawString(model.ylabel, 0+5, d.height/2);
//xaxis
int rows = model.maxy-model.miny+1;
int cols = model.maxx-model.minx+1;
int colWidth = (getWidth()-paddingFromRight - ylabelWidth)/cols;
int rowHeight = (getHeight()-xlabelHeight-headingHeight)/rows;
for (int k = 0;k<=cols;k++)
{
g.drawString(String.valueOf(model.minx+k), ylabelWidth+k*colWidth-5, rowHeight*rows+headingHeight+15);
}
//yaxis
for (int k = 0;k<=rows;k++)
{
g.drawString(String.valueOf(model.maxy-k+1),ylabelWidth-15,headingHeight+k*rowHeight);
}
//heading
FontMetrics fm = g.getFontMetrics();
g.setFont(g.getFont().deriveFont((float)25.0));
g.drawString(model.title, d.width/2-fm.stringWidth(model.title), headingHeight/2+headingHeight/4);
}
I wanted to make a bar chart using java and Swing. I had a look at the code at the link below -
http://www.java2s.com/Code/Java/2D-Graphics-GUI/Simplebarchart.htm
I want to increase the space between bars in this chart. How do I do it?
The code -
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ChartPanel extends JPanel {
private double[] values;
private String[] names;
private String title;
public ChartPanel(double[] v, String[] n, String t) {
names = n;
values = v;
title = t;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (values == null || values.length == 0)
return;
double minValue = 0;
double maxValue = 0;
for (int i = 0; i < values.length; i++) {
if (minValue > values[i])
minValue = values[i];
if (maxValue < values[i])
maxValue = values[i];
}
Dimension d = getSize();
int clientWidth = d.width;
int clientHeight = d.height;
int barWidth = clientWidth / values.length;
Font titleFont = new Font("SansSerif", Font.BOLD, 20);
FontMetrics titleFontMetrics = g.getFontMetrics(titleFont);
Font labelFont = new Font("SansSerif", Font.PLAIN, 10);
FontMetrics labelFontMetrics = g.getFontMetrics(labelFont);
int titleWidth = titleFontMetrics.stringWidth(title);
int y = titleFontMetrics.getAscent();
int x = (clientWidth - titleWidth) / 2;
g.setFont(titleFont);
g.drawString(title, x, y);
int top = titleFontMetrics.getHeight();
int bottom = labelFontMetrics.getHeight();
if (maxValue == minValue)
return;
double scale = (clientHeight - top - bottom) / (maxValue - minValue);
y = clientHeight - labelFontMetrics.getDescent();
g.setFont(labelFont);
for (int i = 0; i < values.length; i++) {
int valueX = i * barWidth + 1;
int valueY = top;
int height = (int) (values[i] * scale);
if (values[i] >= 0)
valueY += (int) ((maxValue - values[i]) * scale);
else {
valueY += (int) (maxValue * scale);
height = -height;
}
g.setColor(Color.red);
g.fillRect(valueX, valueY, barWidth - 2, height);
g.setColor(Color.black);
g.drawRect(valueX, valueY, barWidth - 2, height);
int labelWidth = labelFontMetrics.stringWidth(names[i]);
x = i * barWidth + (barWidth - labelWidth) / 2;
g.drawString(names[i], x, y);
}
}
public static void main(String[] argv) {
JFrame f = new JFrame();
f.setSize(400, 300);
double[] values = new double[3];
String[] names = new String[3];
values[0] = 1;
names[0] = "Item 1";
values[1] = 2;
names[1] = "Item 2";
values[2] = 4;
names[2] = "Item 3";
f.getContentPane().add(new ChartPanel(values, names, "title"));
WindowListener wndCloser = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
f.addWindowListener(wndCloser);
f.setVisible(true);
}
}
Here is a line of code where you set X coordinates for the bars:
int valueX = i * barWidth + 1;
To shift each bar further you can change it to:
int valueX = i * (barWidth+20) + 1;
You can declare a separate class level variable for this:
int barSpace = 20;
...//later in paintComponent.
int valueX = i * (barWidth+space) + 1;
UPDATE: Here is a line of code with calculation of barWidth:
int barWidth = clientWidth / values.length;
To fit your chart in client area you can use the following code:
barWidth-= barSpace; //or barWidth-=20;
This way you will take some space from each bar
I have a gui where data is entered and the averages are calculated for 5 different sets of data. These are stored in an array with the five averages in the five positions.
How do I make it draw rectangles in a jpanel to look like a graph of those 5 averages ?
..make it draw rectangles in a jpanel to look like a graph...
Assuming, youre talking about bar graph,
Have a look at this example :
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SimpleBarChart extends JPanel {
private double[] value;
private String[] languages;
private String title;
public SimpleBarChart(double[] val, String[] lang, String t) {
languages = lang;
value = val;
title = t;
}
#Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
if (value == null || value.length == 0) {
return;
}
double minValue = 0;
double maxValue = 0;
for (int i = 0; i < value.length; i++) {
if (minValue > value[i]) {
minValue = value[i];
}
if (maxValue < value[i]) {
maxValue = value[i];
}
}
Dimension dim = getSize();
int clientWidth = dim.width;
int clientHeight = dim.height;
int barWidth = clientWidth / value.length;
Font titleFont = new Font("Book Antiqua", Font.BOLD, 15);
FontMetrics titleFontMetrics = graphics.getFontMetrics(titleFont);
Font labelFont = new Font("Book Antiqua", Font.PLAIN, 10);
FontMetrics labelFontMetrics = graphics.getFontMetrics(labelFont);
int titleWidth = titleFontMetrics.stringWidth(title);
int q = titleFontMetrics.getAscent();
int p = (clientWidth - titleWidth) / 2;
graphics.setFont(titleFont);
graphics.drawString(title, p, q);
int top = titleFontMetrics.getHeight();
int bottom = labelFontMetrics.getHeight();
if (maxValue == minValue) {
return;
}
double scale = (clientHeight - top - bottom) / (maxValue - minValue);
q = clientHeight - labelFontMetrics.getDescent();
graphics.setFont(labelFont);
for (int j = 0; j < value.length; j++) {
int valueP = j * barWidth + 1;
int valueQ = top;
int height = (int) (value[j] * scale);
if (value[j] >= 0) {
valueQ += (int) ((maxValue - value[j]) * scale);
} else {
valueQ += (int) (maxValue * scale);
height = -height;
}
graphics.setColor(Color.blue);
graphics.fillRect(valueP, valueQ, barWidth - 2, height);
graphics.setColor(Color.black);
graphics.drawRect(valueP, valueQ, barWidth - 2, height);
int labelWidth = labelFontMetrics.stringWidth(languages[j]);
p = j * barWidth + (barWidth - labelWidth) / 2;
graphics.drawString(languages[j], p, q);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(350, 300);
double[] value = new double[5];
String[] languages = new String[5];
value[0] = 1;
languages[0] = "Visual Basic";
value[1] = 2;
languages[1] = "PHP";
value[2] = 3;
languages[2] = "C++";
value[3] = 4;
languages[3] = "C";
value[4] = 5;
languages[4] = "Java";
frame.getContentPane().add(new SimpleBarChart(value, languages,
"Programming Languages"));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Also see JFreeChart and if you dont mind using an external library.
Example that you might need via #trashGod : example and its source code.