Compare commits

...

6 commits

13 changed files with 553 additions and 20874 deletions

1105
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,7 @@ futures = "0.3"
json = "0.12.4" json = "0.12.4"
lazy_static = "1.4" lazy_static = "1.4"
log = "0.4.16" log = "0.4.16"
pdf = "0.7.2" pdf = "0.8"
regex = "1.5.5" regex = "1.5.5"
reqwest = { version = "0.11", features = ["rustls-tls", "stream"], default-features = false } reqwest = { version = "0.11", features = ["rustls-tls", "stream"], default-features = false }
scraper = "0.12" scraper = "0.12"

View file

@ -1,7 +1,7 @@
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use pdf::{backend::Backend, content::Operation, primitive::Primitive}; use pdf::{backend::Backend, content::{Op, Point, TextDrawAdjusted}};
use regex::Regex; use regex::Regex;
use time::Date; use time::Date;
@ -38,7 +38,7 @@ impl DataSet {
if let Some(text) = doc_iter.next() { if let Some(text) = doc_iter.next() {
if is_new_column_header(&text.text) { if is_new_column_header(&text.text) {
let mut column_name = text.text; let mut column_name = text.text;
let column_x = text.x; let column_x = text.point.x;
while let Some(more) = doc_iter.peek() { while let Some(more) = doc_iter.peek() {
if is_new_column_header(&more.text) || DATE_REGEX.is_match(&more.text) { if is_new_column_header(&more.text) || DATE_REGEX.is_match(&more.text) {
columns.push((Arc::new(column_name), column_x)); columns.push((Arc::new(column_name), column_x));
@ -51,7 +51,7 @@ impl DataSet {
} else if DATE_REGEX.is_match(&text.text) { } else if DATE_REGEX.is_match(&text.text) {
break ( break (
DataPoint::new(&text).expect("Failed to parse date!"), DataPoint::new(&text).expect("Failed to parse date!"),
text.y, text.point.y,
); );
} }
} else { } else {
@ -67,12 +67,12 @@ impl DataSet {
&mut current_datapoint, &mut current_datapoint,
DataPoint::new(&text).expect("Failed to parse date!"), DataPoint::new(&text).expect("Failed to parse date!"),
)); ));
current_y = text.y; current_y = text.point.y;
} else if VALUE_REGEX.is_match(&text.text) { } else if VALUE_REGEX.is_match(&text.text) {
if (current_y - text.y).abs() > POSITION_ERROR_MARGIN { if (current_y - text.point.y).abs() > POSITION_ERROR_MARGIN {
continue; continue;
} }
if let Some((column, _)) = columns.iter().rev().find(|(_, x)| *x < text.x) { if let Some((column, _)) = columns.iter().rev().find(|(_, x)| *x < text.point.x) {
current_datapoint.values.insert( current_datapoint.values.insert(
column.clone(), column.clone(),
text.text.parse().expect("Failed to parse value!"), text.text.parse().expect("Failed to parse value!"),
@ -103,26 +103,23 @@ impl DataPoint {
} }
struct DocumentText { struct DocumentText {
x: f32, point: Point,
y: f32,
text: String, text: String,
} }
struct DocumentIterator<'a> { struct DocumentIterator<'a> {
x: f32, point: Point,
y: f32, operations: Box<dyn Iterator<Item = Op> + 'a>,
operations: Box<dyn Iterator<Item = Operation> + 'a>,
} }
impl<'a> DocumentIterator<'a> { impl<'a> DocumentIterator<'a> {
fn new<B: Backend>(document: &'a pdf::file::File<B>) -> Self { fn new<B: Backend>(document: &'a pdf::file::File<B>) -> Self {
Self { Self {
x: 0.0, point: Point { x: 0.0, y: 0.0 },
y: 0.0,
operations: Box::new( operations: Box::new(
document document
.pages() .pages()
.filter_map(|page| Some(page.ok()?.contents.clone()?.operations.into_iter())) .filter_map(|page| Some(page.ok()?.contents.clone()?.operations(document).ok()?.into_iter()))
.flatten(), .flatten(),
), ),
} }
@ -133,54 +130,44 @@ impl<'a> Iterator for DocumentIterator<'a> {
type Item = DocumentText; type Item = DocumentText;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
for Operation { operator, operands } in self.operations.as_mut() { for operation in self.operations.as_mut() {
if operator == "Tm" { match operation {
if let (Some(x), Some(y)) = ( Op::SetTextMatrix { matrix } => {
operands.get(4).and_then(extract_number), self.point = Point { x: matrix.e, y: matrix.f };
operands.get(5).and_then(extract_number),
) {
self.x = x;
self.y = y;
} }
} else if operator == "TJ" || operator == "Tj" { Op::TextDraw { text } => {
if let Some(text) = operands.get(0).and_then(extract_string) { if let Ok(text) = text.to_string() {
return Some(DocumentText { return Some(DocumentText {
x: self.x, point: self.point,
y: self.y, text,
text, });
}); }
} }
Op::TextDrawAdjusted { array } => {
if let Some(text) = concatenate_adjusted_text(array) {
return Some(DocumentText {
point: self.point,
text,
});
}
}
_ => continue,
} }
} }
None None
} }
} }
fn extract_number(p: &Primitive) -> Option<f32> { fn concatenate_adjusted_text(array: Vec<TextDrawAdjusted>) -> Option<String> {
match p { let mut acc = String::new();
Primitive::Number(n) => Some(*n), for element in array.iter() {
Primitive::Integer(n) => Some(*n as f32), if let TextDrawAdjusted::Text(s) = element {
_ => None, acc += s.to_string().ok()?.as_ref();
}
}
fn extract_string(p: &Primitive) -> Option<String> {
let result: Box<dyn AsRef<str>> = match p {
Primitive::Array(array) => {
let mut acc = String::new();
for element in array.iter() {
if let Primitive::String(s) = element {
acc += s.as_str().ok()?.as_ref();
}
}
Box::new(acc)
} }
Primitive::String(s) => Box::new(s.as_str().ok()?),
_ => return None,
}; };
Some( Some(
WHITESPACE_REGEX WHITESPACE_REGEX
.replace_all((*result).as_ref().trim(), " ") .replace_all(acc.trim(), " ")
.to_string(), .to_string(),
) )
} }

File diff suppressed because it is too large Load diff

14
static/chart.umd.js Normal file

File diff suppressed because one or more lines are too long

1
static/chart.umd.js.map Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,606 +0,0 @@
/**
* chartjs-chart-error-bars
* https://github.com/sgratzl/chartjs-chart-error-bars
*
* Copyright (c) 2021 Samuel Gratzl <samu@sgratzl.com>
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('chart.js'), require('chart.js/helpers')) :
typeof define === 'function' && define.amd ? define(['exports', 'chart.js', 'chart.js/helpers'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ChartErrorBars = {}, global.Chart, global.Chart.helpers));
})(this, (function (exports, chart_js, helpers) { 'use strict';
const allModelKeys = ['xMin', 'xMax', 'yMin', 'yMax'];
function modelKeys(horizontal) {
return (horizontal ? allModelKeys.slice(0, 2) : allModelKeys.slice(2));
}
function calculateScale(properties, data, index, scale, reset) {
const keys = [`${scale.axis}Min`, `${scale.axis}Max`];
const base = scale.getBasePixel();
for (const key of keys) {
const v = data[key];
if (Array.isArray(v)) {
properties[key] = v.map((d) => (reset ? base : scale.getPixelForValue(d, index)));
}
else if (typeof v === 'number') {
properties[key] = reset ? base : scale.getPixelForValue(v, index);
}
}
}
function calculatePolarScale(properties, data, scale, reset, options) {
const animationOpts = options.animation;
const keys = [`${scale.axis}Min`, `${scale.axis}Max`];
const toAngle = (v) => {
const valueRadius = scale.getDistanceFromCenterForValue(v);
const resetRadius = animationOpts.animateScale ? 0 : valueRadius;
return reset ? resetRadius : valueRadius;
};
for (const key of keys) {
const v = data[key];
if (Array.isArray(v)) {
properties[key] = v.map(toAngle);
}
else if (typeof v === 'number') {
properties[key] = toAngle(v);
}
}
}
const errorBarDefaults = {
errorBarLineWidth: { v: [1, 3] },
errorBarColor: { v: ['#2c2c2c', '#1f1f1f'] },
errorBarWhiskerLineWidth: { v: [1, 3] },
errorBarWhiskerRatio: { v: [0.2, 0.25] },
errorBarWhiskerSize: { v: [20, 24] },
errorBarWhiskerColor: { v: ['#2c2c2c', '#1f1f1f'] },
};
const errorBarDescriptors = {
_scriptable: true,
_indexable: (name) => name !== 'v',
};
const styleKeys = Object.keys(errorBarDefaults);
function resolveMulti(vMin, vMax) {
const vMinArr = Array.isArray(vMin) ? vMin : [vMin];
const vMaxArr = Array.isArray(vMax) ? vMax : [vMax];
if (vMinArr.length === vMaxArr.length) {
return vMinArr.map((v, i) => [v, vMaxArr[i]]);
}
const max = Math.max(vMinArr.length, vMaxArr.length);
return Array(max).map((_, i) => [vMinArr[i % vMinArr.length], vMaxArr[i % vMaxArr.length]]);
}
function resolveOption(val, index) {
if (typeof val === 'string' || typeof val === 'number') {
return val;
}
const v = Array.isArray(val) ? val : val.v;
return v[index % v.length];
}
function calculateHalfSize(total, options, i) {
const ratio = resolveOption(options.errorBarWhiskerRatio, i);
if (total != null && ratio > 0) {
return total * ratio * 0.5;
}
const size = resolveOption(options.errorBarWhiskerSize, i);
return size * 0.5;
}
function drawErrorBarVertical(props, vMin, vMax, options, ctx) {
ctx.save();
ctx.translate(props.x, 0);
const bars = resolveMulti(vMin == null ? props.y : vMin, vMax == null ? props.y : vMax);
bars.reverse().forEach(([mi, ma], j) => {
const i = bars.length - j - 1;
const halfWidth = calculateHalfSize(props.width, options, i);
ctx.lineWidth = resolveOption(options.errorBarLineWidth, i);
ctx.strokeStyle = resolveOption(options.errorBarColor, i);
ctx.beginPath();
ctx.moveTo(0, mi);
ctx.lineTo(0, ma);
ctx.stroke();
ctx.lineWidth = resolveOption(options.errorBarWhiskerLineWidth, i);
ctx.strokeStyle = resolveOption(options.errorBarWhiskerColor, i);
ctx.beginPath();
ctx.moveTo(-halfWidth, mi);
ctx.lineTo(halfWidth, mi);
ctx.moveTo(-halfWidth, ma);
ctx.lineTo(halfWidth, ma);
ctx.stroke();
});
ctx.restore();
}
function drawErrorBarHorizontal(props, vMin, vMax, options, ctx) {
ctx.save();
ctx.translate(0, props.y);
const bars = resolveMulti(vMin == null ? props.x : vMin, vMax == null ? props.x : vMax);
bars.reverse().forEach(([mi, ma], j) => {
const i = bars.length - j - 1;
const halfHeight = calculateHalfSize(props.height, options, i);
ctx.lineWidth = resolveOption(options.errorBarLineWidth, i);
ctx.strokeStyle = resolveOption(options.errorBarColor, i);
ctx.beginPath();
ctx.moveTo(mi, 0);
ctx.lineTo(ma, 0);
ctx.stroke();
ctx.lineWidth = resolveOption(options.errorBarWhiskerLineWidth, i);
ctx.strokeStyle = resolveOption(options.errorBarWhiskerColor, i);
ctx.beginPath();
ctx.moveTo(mi, -halfHeight);
ctx.lineTo(mi, halfHeight);
ctx.moveTo(ma, -halfHeight);
ctx.lineTo(ma, halfHeight);
ctx.stroke();
});
ctx.restore();
}
function renderErrorBar(elem, ctx) {
var _a, _b, _c, _d;
const props = elem.getProps(['x', 'y', 'width', 'height', 'xMin', 'xMax', 'yMin', 'yMax']);
if (props.xMin != null || props.xMax != null) {
drawErrorBarHorizontal(props, (_a = props.xMin) !== null && _a !== void 0 ? _a : null, (_b = props.xMax) !== null && _b !== void 0 ? _b : null, elem.options, ctx);
}
if (props.yMin != null || props.yMax != null) {
drawErrorBarVertical(props, (_c = props.yMin) !== null && _c !== void 0 ? _c : null, (_d = props.yMax) !== null && _d !== void 0 ? _d : null, elem.options, ctx);
}
}
function drawErrorBarArc(props, vMin, vMax, options, ctx) {
ctx.save();
ctx.translate(props.x, props.y);
const angle = (props.startAngle + props.endAngle) / 2;
const cosAngle = Math.cos(angle);
const sinAngle = Math.sin(angle);
const v = {
x: -sinAngle,
y: cosAngle,
};
const length = Math.sqrt(v.x * v.x + v.y * v.y);
v.x /= length;
v.y /= length;
const bars = resolveMulti(vMin !== null && vMin !== void 0 ? vMin : props.outerRadius, vMax !== null && vMax !== void 0 ? vMax : props.outerRadius);
bars.reverse().forEach(([mi, ma], j) => {
const i = bars.length - j - 1;
const minCos = mi * cosAngle;
const minSin = mi * sinAngle;
const maxCos = ma * cosAngle;
const maxSin = ma * sinAngle;
const halfHeight = calculateHalfSize(null, options, i);
const eX = v.x * halfHeight;
const eY = v.y * halfHeight;
ctx.lineWidth = resolveOption(options.errorBarLineWidth, i);
ctx.strokeStyle = resolveOption(options.errorBarColor, i);
ctx.beginPath();
ctx.moveTo(minCos, minSin);
ctx.lineTo(maxCos, maxSin);
ctx.stroke();
ctx.lineWidth = resolveOption(options.errorBarWhiskerLineWidth, i);
ctx.strokeStyle = resolveOption(options.errorBarWhiskerColor, i);
ctx.beginPath();
ctx.moveTo(minCos + eX, minSin + eY);
ctx.lineTo(minCos - eX, minSin - eY);
ctx.moveTo(maxCos + eX, maxSin + eY);
ctx.lineTo(maxCos - eX, maxSin - eY);
ctx.stroke();
});
ctx.restore();
}
function renderErrorBarArc(elem, ctx) {
const props = elem.getProps(['x', 'y', 'startAngle', 'endAngle', 'rMin', 'rMax', 'outerRadius']);
if (props.rMin != null || props.rMax != null) {
drawErrorBarArc(props, props.rMin, props.rMax, elem.options, ctx);
}
}
class BarWithErrorBar extends chart_js.BarElement {
draw(ctx) {
super.draw(ctx);
renderErrorBar(this, ctx);
}
}
BarWithErrorBar.id = 'barWithErrorBar';
BarWithErrorBar.defaults = { ...chart_js.BarElement.defaults, ...errorBarDefaults };
BarWithErrorBar.defaultRoutes = chart_js.BarElement.defaultRoutes;
BarWithErrorBar.descriptors = errorBarDescriptors;
class PointWithErrorBar extends chart_js.PointElement {
draw(ctx, area) {
super.draw.call(this, ctx, area);
renderErrorBar(this, ctx);
}
}
PointWithErrorBar.id = 'pointWithErrorBar';
PointWithErrorBar.defaults = { ...chart_js.PointElement.defaults, ...errorBarDefaults };
PointWithErrorBar.defaultRoutes = chart_js.PointElement.defaultRoutes;
PointWithErrorBar.descriptors = errorBarDescriptors;
class ArcWithErrorBar extends chart_js.ArcElement {
draw(ctx) {
super.draw(ctx);
renderErrorBarArc(this, ctx);
}
}
ArcWithErrorBar.id = 'arcWithErrorBar';
ArcWithErrorBar.defaults = { ...chart_js.ArcElement.defaults, ...errorBarDefaults };
ArcWithErrorBar.defaultRoutes = chart_js.ArcElement.defaultRoutes;
ArcWithErrorBar.descriptors = errorBarDescriptors;
function reverseOrder(v) {
return Array.isArray(v) ? v.slice().reverse() : v;
}
function generateBarTooltip(item) {
const keys = modelKeys(item.element.horizontal);
const base = chart_js.Tooltip.defaults.callbacks.label.call(this, item);
const v = item.chart.data.datasets[item.datasetIndex].data[item.dataIndex];
if (v == null || keys.every((k) => v[k] == null)) {
return base;
}
return `${base} (${reverseOrder(v[keys[0]])} .. ${v[keys[1]]})`;
}
function generateTooltipScatter(item) {
const v = item.chart.data.datasets[item.datasetIndex].data[item.dataIndex];
const subLabel = (base, horizontal) => {
const keys = modelKeys(horizontal);
if (v == null || keys.every((k) => v[k] == null)) {
return base;
}
return `${base} [${reverseOrder(v[keys[0]])} .. ${v[keys[1]]}]`;
};
return `(${subLabel(item.label, true)}, ${subLabel(item.parsed.y, false)})`;
}
function generateTooltipPolar(item) {
const base = chart_js.PolarAreaController.overrides.plugins.tooltip.callbacks.label.call(this, item);
const v = item.chart.data.datasets[item.datasetIndex].data[item.dataIndex];
const keys = ['rMin', 'rMax'];
if (v == null || keys.every((k) => v[k] == null)) {
return base;
}
return `${base} [${reverseOrder(v[keys[0]])} .. ${v[keys[1]]}]`;
}
const interpolators = {
color(from, to, factor) {
const f = from || 'transparent';
const t = to || 'transparent';
if (f === t) {
return to;
}
const c0 = helpers.color(f);
const c1 = c0.valid && helpers.color(t);
return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to;
},
number(from, to, factor) {
if (from === to) {
return to;
}
return from + (to - from) * factor;
},
};
function interpolateArrayOption(from, to, factor, type, interpolator) {
if (typeof from === type && typeof to === type) {
return interpolator(from, to, factor);
}
if (Array.isArray(from) && Array.isArray(to)) {
return from.map((f, i) => interpolator(f, to[i], factor));
}
const isV = (t) => t && Array.isArray(t.v);
if (isV(from) && isV(to)) {
return { v: from.v.map((f, i) => interpolator(f, to.v[i], factor)) };
}
return to;
}
function interpolateNumberOptionArray(from, to, factor) {
return interpolateArrayOption(from, to, factor, 'number', interpolators.number);
}
function interpolateColorOptionArray(from, to, factor) {
return interpolateArrayOption(from, to, factor, 'string', interpolators.color);
}
const animationHints = {
animations: {
numberArray: {
fn: interpolateNumberOptionArray,
properties: allModelKeys.concat(styleKeys.filter((d) => !d.endsWith('Color')), ['rMin', 'rMax']),
},
colorArray: {
fn: interpolateColorOptionArray,
properties: styleKeys.filter((d) => d.endsWith('Color')),
},
},
};
function getMinMax(scale, superMethod) {
const { axis } = scale;
scale.axis = `${axis}MinMin`;
const { min } = superMethod(scale);
scale.axis = `${axis}MaxMax`;
const { max } = superMethod(scale);
scale.axis = axis;
return { min, max };
}
function computeExtrema(v, vm, op) {
if (Array.isArray(vm)) {
return op(...vm);
}
if (typeof vm === 'number') {
return vm;
}
return v;
}
function parseErrorNumberData(parsed, scale, data, start, count) {
const axis = typeof scale === 'string' ? scale : scale.axis;
const vMin = `${axis}Min`;
const vMax = `${axis}Max`;
const vMinMin = `${axis}MinMin`;
const vMaxMax = `${axis}MaxMax`;
for (let i = 0; i < count; i += 1) {
const index = i + start;
const p = parsed[i];
p[vMin] = data[index][vMin];
p[vMax] = data[index][vMax];
p[vMinMin] = computeExtrema(p[axis], p[vMin], Math.min);
p[vMaxMax] = computeExtrema(p[axis], p[vMax], Math.max);
}
}
function parseErrorLabelData(parsed, scale, start, count) {
const { axis } = scale;
const labels = scale.getLabels();
for (let i = 0; i < count; i += 1) {
const index = i + start;
const p = parsed[i];
p[axis] = scale.parse(labels[index], index);
}
}
function patchController(type, config, controller, elements = [], scales = []) {
chart_js.registry.addControllers(controller);
if (Array.isArray(elements)) {
chart_js.registry.addElements(...elements);
}
else {
chart_js.registry.addElements(elements);
}
if (Array.isArray(scales)) {
chart_js.registry.addScales(...scales);
}
else {
chart_js.registry.addScales(scales);
}
const c = config;
c.type = type;
return c;
}
class BarWithErrorBarsController extends chart_js.BarController {
getMinMax(scale, canStack) {
return getMinMax(scale, (patchedScale) => super.getMinMax(patchedScale, canStack));
}
parseObjectData(meta, data, start, count) {
const parsed = super.parseObjectData(meta, data, start, count);
parseErrorNumberData(parsed, meta.vScale, data, start, count);
parseErrorLabelData(parsed, meta.iScale, start, count);
return parsed;
}
updateElement(element, index, properties, mode) {
if (typeof index === 'number') {
calculateScale(properties, this.getParsed(index), index, this._cachedMeta.vScale, mode === 'reset');
}
super.updateElement(element, index, properties, mode);
}
}
BarWithErrorBarsController.id = 'barWithErrorBars';
BarWithErrorBarsController.defaults = helpers.merge({}, [
chart_js.BarController.defaults,
animationHints,
{
dataElementType: BarWithErrorBar.id,
},
]);
BarWithErrorBarsController.overrides = helpers.merge({}, [
chart_js.BarController.overrides,
{
plugins: {
tooltip: {
callbacks: {
label: generateBarTooltip,
},
},
},
},
]);
BarWithErrorBarsController.defaultRoutes = chart_js.BarController.defaultRoutes;
class BarWithErrorBarsChart extends chart_js.Chart {
constructor(item, config) {
super(item, patchController('barWithErrorBars', config, BarWithErrorBarsController, BarWithErrorBar, [
chart_js.LinearScale,
chart_js.CategoryScale,
]));
}
}
BarWithErrorBarsChart.id = BarWithErrorBarsController.id;
class LineWithErrorBarsController extends chart_js.LineController {
getMinMax(scale, canStack) {
return getMinMax(scale, (patchedScale) => super.getMinMax(patchedScale, canStack));
}
parseObjectData(meta, data, start, count) {
const parsed = super.parseObjectData(meta, data, start, count);
parseErrorNumberData(parsed, meta.vScale, data, start, count);
parseErrorLabelData(parsed, meta.iScale, start, count);
return parsed;
}
updateElement(element, index, properties, mode) {
if (element instanceof PointWithErrorBar && typeof index === 'number') {
calculateScale(properties, this.getParsed(index), index, this._cachedMeta.vScale, mode === 'reset');
}
super.updateElement(element, index, properties, mode);
}
}
LineWithErrorBarsController.id = 'lineWithErrorBars';
LineWithErrorBarsController.defaults = helpers.merge({}, [
chart_js.LineController.defaults,
animationHints,
{
dataElementType: PointWithErrorBar.id,
},
]);
LineWithErrorBarsController.overrides = helpers.merge({}, [
chart_js.LineController.overrides,
{
plugins: {
tooltip: {
callbacks: {
label: generateBarTooltip,
},
},
},
},
]);
LineWithErrorBarsController.defaultRoutes = chart_js.LineController.defaultRoutes;
class LineWithErrorBarsChart extends chart_js.Chart {
constructor(item, config) {
super(item, patchController('lineWithErrorBars', config, LineWithErrorBarsController, PointWithErrorBar, [
chart_js.LinearScale,
chart_js.CategoryScale,
]));
}
}
LineWithErrorBarsChart.id = LineWithErrorBarsController.id;
class ScatterWithErrorBarsController extends chart_js.ScatterController {
getMinMax(scale, canStack) {
return getMinMax(scale, (patchedScale) => super.getMinMax(patchedScale, canStack));
}
parseObjectData(meta, data, start, count) {
const parsed = super.parseObjectData(meta, data, start, count);
parseErrorNumberData(parsed, meta.xScale, data, start, count);
parseErrorNumberData(parsed, meta.yScale, data, start, count);
return parsed;
}
updateElement(element, index, properties, mode) {
if (element instanceof PointWithErrorBar && typeof index === 'number') {
calculateScale(properties, this.getParsed(index), index, this._cachedMeta.xScale, mode === 'reset');
calculateScale(properties, this.getParsed(index), index, this._cachedMeta.yScale, mode === 'reset');
}
super.updateElement(element, index, properties, mode);
}
}
ScatterWithErrorBarsController.id = 'scatterWithErrorBars';
ScatterWithErrorBarsController.defaults = helpers.merge({}, [
chart_js.ScatterController.defaults,
animationHints,
{
dataElementType: PointWithErrorBar.id,
},
]);
ScatterWithErrorBarsController.overrides = helpers.merge({}, [
chart_js.ScatterController.overrides,
{
plugins: {
tooltip: {
callbacks: {
label: generateTooltipScatter,
},
},
},
},
]);
ScatterWithErrorBarsController.defaultRoutes = chart_js.LineController.defaultRoutes;
class ScatterWithErrorBarsChart extends chart_js.Chart {
constructor(item, config) {
super(item, patchController('scatterWithErrorBars', config, ScatterWithErrorBarsController, PointWithErrorBar, [chart_js.LinearScale]));
}
}
ScatterWithErrorBarsChart.id = ScatterWithErrorBarsController.id;
class PolarAreaWithErrorBarsController extends chart_js.PolarAreaController {
getMinMax(scale, canStack) {
return getMinMax(scale, (patchedScale) => super.getMinMax(patchedScale, canStack));
}
countVisibleElements() {
const meta = this._cachedMeta;
return meta.data.reduce((acc, _, index) => {
if (!Number.isNaN(meta._parsed[index].r) && this.chart.getDataVisibility(index)) {
return acc + 1;
}
return acc;
}, 0);
}
parseObjectData(meta, data, start, count) {
const parsed = new Array(count);
const scale = meta.rScale;
for (let i = 0; i < count; i += 1) {
const index = i + start;
const item = data[index];
const v = scale.parse(item[scale.axis], index);
parsed[i] = {
[scale.axis]: v,
};
}
parseErrorNumberData(parsed, scale, data, start, count);
return parsed;
}
updateElement(element, index, properties, mode) {
if (typeof index === 'number') {
calculatePolarScale(properties, this.getParsed(index), this._cachedMeta.rScale, mode === 'reset', this.chart.options);
}
super.updateElement(element, index, properties, mode);
}
updateElements(arcs, start, count, mode) {
const scale = this.chart.scales.r;
const bak = scale.getDistanceFromCenterForValue;
scale.getDistanceFromCenterForValue = function getDistanceFromCenterForValue(v) {
if (typeof v === 'number') {
return bak.call(this, v);
}
return bak.call(this, v.r);
};
super.updateElements(arcs, start, count, mode);
scale.getDistanceFromCenterForValue = bak;
}
}
PolarAreaWithErrorBarsController.id = 'polarAreaWithErrorBars';
PolarAreaWithErrorBarsController.defaults = helpers.merge({}, [
chart_js.PolarAreaController.defaults,
animationHints,
{
dataElementType: ArcWithErrorBar.id,
},
]);
PolarAreaWithErrorBarsController.overrides = helpers.merge({}, [
chart_js.PolarAreaController.overrides,
{
plugins: {
tooltip: {
callbacks: {
label: generateTooltipPolar,
},
},
},
},
]);
PolarAreaWithErrorBarsController.defaultRoutes = chart_js.PolarAreaController.defaultRoutes;
class PolarAreaWithErrorBarsChart extends chart_js.Chart {
constructor(item, config) {
super(item, patchController('polarAreaWithErrorBars', config, PolarAreaWithErrorBarsController, ArcWithErrorBar, [
chart_js.RadialLinearScale,
]));
}
}
PolarAreaWithErrorBarsChart.id = PolarAreaWithErrorBarsController.id;
chart_js.registry.addControllers(BarWithErrorBarsController, LineWithErrorBarsController, PolarAreaWithErrorBarsController, ScatterWithErrorBarsController);
chart_js.registry.addElements(BarWithErrorBar, ArcWithErrorBar, PointWithErrorBar);
exports.ArcWithErrorBar = ArcWithErrorBar;
exports.BarWithErrorBar = BarWithErrorBar;
exports.BarWithErrorBarsChart = BarWithErrorBarsChart;
exports.BarWithErrorBarsController = BarWithErrorBarsController;
exports.LineWithErrorBarsChart = LineWithErrorBarsChart;
exports.LineWithErrorBarsController = LineWithErrorBarsController;
exports.PointWithErrorBar = PointWithErrorBar;
exports.PolarAreaWithErrorBarsChart = PolarAreaWithErrorBarsChart;
exports.PolarAreaWithErrorBarsController = PolarAreaWithErrorBarsController;
exports.ScatterWithErrorBarsChart = ScatterWithErrorBarsChart;
exports.ScatterWithErrorBarsController = ScatterWithErrorBarsController;
Object.defineProperty(exports, '__esModule', { value: true });
}));
//# sourceMappingURL=index.umd.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,9 +3,9 @@
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<script src="chart.js"></script> <script src="chart.umd.js"></script>
<script src="chartjs-adapter-date-fns.bundle.js"></script> <script src="chartjs-adapter-date-fns.bundle.min.js"></script>
<script src="chartjs-chart-error-bars.umd.js"></script> <script src="chartjs-chart-error-bars.umd.min.js"></script>
<style> <style>
body { body {
text-align: center; text-align: center;

View file

@ -192,13 +192,13 @@ function plot(data) {
data: { data: {
datasets: [ datasets: [
{ {
type: 'scatterWithErrorBars', type: 'lineWithErrorBars',
label: 'Measured value', label: 'Measured value',
data: northData, data: northData,
backgroundColor: 'rgba(0,0,255,0.5)', backgroundColor: 'rgba(0,0,255,0.5)',
color: 'rgba(0,0,255,0.5)', color: 'rgba(0,0,255,0.5)',
borderColor: 'rgba(0,0,255,0.5)', borderColor: 'rgba(0,0,255,0.5)',
spanGaps: true, showLine: false,
}, },
/* { /* {
type: 'line', type: 'line',
@ -248,13 +248,13 @@ function plot(data) {
data: { data: {
datasets: [ datasets: [
{ {
type: 'scatterWithErrorBars', type: 'lineWithErrorBars',
label: 'Measured value', label: 'Measured value',
data: southData, data: southData,
backgroundColor: 'rgba(255,0,0,0.5)', backgroundColor: 'rgba(255,0,0,0.5)',
color: 'rgba(255,0,0,0.5)', color: 'rgba(255,0,0,0.5)',
borderColor: 'rgba(255,0,0,0.5)', borderColor: 'rgba(255,0,0,0.5)',
spanGaps: true, showLine: false,
}, },
{ {
type: 'line', type: 'line',