First commit

This commit is contained in:
linarphy 2023-12-30 21:47:55 +01:00
commit 3176e4fdf6
No known key found for this signature in database
GPG key ID: 0610ABB68DAA7B65
8 changed files with 510 additions and 0 deletions

32
README.md Normal file
View file

@ -0,0 +1,32 @@
# lichartee
Clone of [matplotlib](https://matplotlib.org) in javascript
## Getting started
Download or clone this repo, then open [index.html](index.html) in your
favorite browser.
[test.js](test.js) present an example use of this library.
## Documentation
WIP
## Author
- linarphy - *initial work*
## Versioning
We use [Semver](http://semver.org) for versioning.
## License
This project is licensied under the Chocolate-Ware license - see the
[LICENSE](LICENSE) file for more information.
## Changelog
*v.0.1*
- creation of a basic layout

87
favicon.svg Normal file
View file

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<!-- Edited with neovim (Neovide for windows) -->
<svg
width="500"
height="500"
version="2.0"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<style>
path
{
fill: #000000;
}
@media (prefers-color-scheme: dark)
{
path
{
fill: #ffffff;
}
}
</style>
<title>
lichartee logo
</title>
<path
d="M 250,500 H 0 V 0 L 73.2233,73.2233 V 426.7767 c 0,0 60.78,72.95 179.20,72.19"
id="bar_left" />
<path
d="M 250,500 H 500 V 0 L 426.7767,73.2233 V 426.7767 c 0,0 -58.26,72.95 -177.94,72.19"
id="bar_right" />
<path
d="M 375,125 250,250 125,125 c -33.527221,33.35835 -52.451433,78.65491 -52.62,125.95 0,98.62149 79.94851,178.57 178.57,178.57 98.62149,0 178.57,-79.94851 178.57,-178.57 C 429.35143,203.65491 408.52722,158.35835 375,125 Z"
id="circle" />
<path
d="M 250,0 125,125 c 34.60338,-29.864158 79.34131,-45.322007 125,-43.19 46.91963,0.333871 86.51935,10.011293 125,43.19 z"
id="top" />
<metadata>
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:title>lichartee logo</dc:title>
<dc:date>2023/12/30</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>linarphy</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>logo</rdf:li>
<rdf:li>char</rdf:li>
<rdf:li>lichartee</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:rights>
<cc:Agent>
<dc:title>ArtLibre</dc:title>
</cc:Agent>
</dc:rights>
<cc:license
rdf:resource="http://artlibre.org/licence/lal" />
</cc:Work>
<cc:License
rdf:about="http://artlibre.org/licence/lal">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
</cc:License>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

9
humans.txt Normal file
View file

@ -0,0 +1,9 @@
/* TEAM */
Dev: linarphy
Fediverse: @linarphy@linarphy.net
/* SITE */
Last update: 2023/12/30
Language: English
Doctype: HTML5
IDE: neovim

29
index.html Normal file
View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="description"
content="A small demo of this plotting library" />
<meta name="author" content="linarphy" />
<meta name="keywords" content="chart,plot,js,library" />
<meta name="generator" content="neovim" />
<link type="text/plain" rel="author" href="humans.txt" />
<link type="image/svg+xml" rel="icon" href="favicon.svg" />
<link rel="stylesheet" href="main.css" />
<title>Chart demo</title>
<script src="main.js"></script>
<!-- Added by include() -->
</head>
<body>
<header>
Multiple plot
</header>
<main>
</main>
<footer>
<a href="https://git.linarphy.net/linarphy/lichartee" title="Source of this code">
code
</a>
</footer>
</body>
</html>

281
lichartee.js Normal file
View file

@ -0,0 +1,281 @@
class Manager
{
constructor(parent_element)
{
this.parent_element = parent_element;
this.list_canvas = [];
}
/**
* add a canvas
*
* @param int width Width of the added canvas
* @param int height Height of the added canvas
* @param int position Subjective position of the added canvas
*/
add_canvas(width = 100, height = 100, position = 0)
{
let element_canvas = document.createElement('canvas');
let text = document.createTextNode(
'Your browser doesn\'t seem to support canvas, or you ' +
'deactivated them. This is the canvas where the chart ' +
'should be displayed'
);
element_canvas.appendChild(text);
if (this.parent_element.childElementCount === 0)
{
this.parent_element.appendChild(element_canvas);
}
else
{
this.parent_element.children[position].before(
element_canvas
);
}
let ctx = element_canvas.getContext('2d');
ctx.canvas.width = width ;
ctx.canvas.height = height;
let figure = new Figure();
let canvas = new Canvas(ctx, figure);
this.list_canvas.splice(position, 0, canvas);
return canvas;
}
draw()
{
for (const index in this.list_canvas)
{
this.list_canvas[index].draw();
}
}
remove_canvas(position = 0)
{
document.removeChild(this.list_canvas[position].ctx.canvas);
this.list_canvas.splice(position, 1);
}
}
class Canvas
{
constructor(ctx, figure)
{
this.ctx = ctx ;
this.figure = figure;
}
draw()
{
if (this.figure instanceof Figure.constructor)
{
throw _('this canvas does not possess figure to draw')
}
let start_x = 0;
for (const index_axes in this.figure.list_axes)
{
let axes = this.figure.list_axes[index_axes];
let x_proportion = axes.width/this.figure.width
this.ctx.beginPath();
this.ctx.moveTo(
start_x,
0
);
this.ctx.lineTo(
start_x ,
this.ctx.canvas.height
);
let end_x = start_x + this.ctx.canvas.width * x_proportion
this.ctx.lineTo(
end_x ,
this.ctx.canvas.height
);
this.ctx.lineTo(
end_x,
0
);
this.ctx.lineTo(
start_x,
0
);
this.ctx.strokeStyle = 'rgb(0,0,0)';
this.ctx.stroke();
const x_min = get_ext_array(
axes.lines.map(
(element) => element.x.reduce(
(a, b) => Math.min(a, b),
Infinity
)
) ,
Math.min,
1
);
const y_min = get_ext_array(
axes.lines.map(
(element) => element.y.reduce(
(a, b) => Math.min(a, b),
Infinity
)
) ,
Math.min,
1
);
const x_max = get_ext_array(
axes.lines.map(
(element) => element.x.reduce(
(a, b) => Math.max(a, b),
-Infinity
)
)
);
const y_max = get_ext_array(
axes.lines.map(
(element) => element.y.reduce(
(a, b) => Math.max(a, b),
-Infinity
)
)
);
for (const index_line in axes.lines)
{
axes.lines[index_line].draw(
this.ctx ,
[[start_x, 0],[end_x, this.ctx.canvas.height]],
[[x_min, y_min], [x_max, y_max]]
);
}
start_x = end_x;
}
}
}
class Figure
{
constructor()
{
this.width = 0 ;
this.height = 0 ;
this.list_axes = [];
}
add_axes(relative_width = 50, relative_height = 50, position = 0)
{
this.width += relative_width ;
this.height += relative_height;
let axes = new Axes(relative_width, relative_height);
this.list_axes.splice(position, 0, axes);
return axes;
}
remove_axes(position)
{
this.list_axes.splice(position, 1);
}
}
class Axes
{
constructor(
width = 100 ,
height = 100 ,
position = 0 ,
title = '' ,
)
{
this.width = width ;
this.height = height ;
this.position = position;
this.title = title ;
this.lines = [] ;
}
plot(x, y, linestyle = undefined, label = '')
{
if (linestyle === undefined)
{
linestyle = new Style();
}
let line = new Line(x, y, linestyle, label);
this.lines.push(line);
}
}
class Line
{
constructor(
x ,
y ,
linestyle = undefined ,
label = ''
)
{
this.x = x ;
this.y = y ;
this.linestyle = linestyle ;
this.label = label ;
}
/**
* draw the line in the box coordinate
*
* @param ctx ctx Context of the canvas
* @param 2dlist<int> box Box where to draw the line
* @param 2dlist<float> view Scale of the box (link value <->
* coordinate
*/
draw(ctx, box, view)
{
const x_delta = view[1][0] - view[0][0];
const y_delta = view[1][1] - view[0][1];
const box_width = box[1][0] - box[0][0];
const box_height = box[1][1] - box[0][1];
let x_coordinates = this.x.map(
function (element, index, array)
{
return box[0][0] + box_width * (
element - view[0][0]
) / x_delta;
}
);
let y_coordinates = this.y.map(
function (element, index, array)
{
return box[0][1] + box_height - ( // starting top left
box_height * (
element - view[0][1]
) / y_delta
);
}
);
ctx.moveTo(
x_coordinates[0],
y_coordinates[0]
);
for (const index in x_coordinates)
{
ctx.lineTo(
x_coordinates[index],
y_coordinates[index]
);
}
ctx.strokeStyle = this.linestyle.color;
ctx.stroke();
}
}
class Style
{
constructor(color = "rgb(0,0,0)", style = 'solid')
{
this.color = color;
this.style = style;
}
}
function get_ext_array(array, f = Math.max, sign = -1)
{
return array.reduce(
(a, b) => f(a, b),
sign * Infinity
);
}

1
main.css Normal file
View file

@ -0,0 +1 @@

58
main.js Normal file
View file

@ -0,0 +1,58 @@
/*
* GLOBAL VARIABLE!
* list of loaded scripts (only itself at start)
**/
var __scripts = [ 'main.js' ];
//var __lang = 'en';
/* i18n small function */
function _(key)
{
return key;
//return LANG[__lang][key] == undefined ? key : LANG[__lang][key];
}
/* include other scripts to the html file */
async function include(src, script_list)
{
/* DOM operations */
let script = document.createElement('script');
script.setAttribute('src' , src );
document.getElementsByTagName('head')[0].appendChild(script);
/* check if the element is added to the DOM */
let script_loaded = new Promise( (resolve, reject) => {
if (script !== undefined)
{
script.addEventListener('load', () => {
resolve(0);
});
}
else
{
reject(
_(
'an error occured when adding the script element' +
'for ${src}'
)
);
}
} );
script_list.push(src); // the script is considered as loaded
return script_loaded.then(
(value) => script_list,
(error) => {
throw error;
}
);
}
async function launch()
{
__scripts = await include('./lichartee.js', __scripts);
__scripts = await include('./test.js', __scripts);
}
launch()

13
test.js Normal file
View file

@ -0,0 +1,13 @@
let manager = new Manager(
document.getElementsByTagName('main')[0]
);
manager.add_canvas(500, 500);
manager.add_canvas(500, 500).figure.add_axes().plot(
[0,1,2,3,4,5] ,
[0,1,4,9,16,25],
);
manager.list_canvas[0].figure.list_axes[0].plot(
[0,1,2,3,4,5],
[0,2,4,6,8,10]
);
manager.draw();