<html>
<!-- chart объявлен в самом низу-->
<canvas onmousemove="chart.onMouseMove(event)" id="canvas"></canvas>
...
...
...
</html>
<script>
var Chart = function(data) {
this.prototype = Object.prototype;
this.data = data;
this.canvas = document.getElementById("canvas");
if (!this.canvas.getContext) return null;
//Трюк для увеличения DPI canvas'a
this.scaleFactor = 8;
this.canvas.width = Math.ceil(this.canvas.width * this.scaleFactor);
this.canvas.height = Math.ceil(this.canvas.height * this.scaleFactor);
this.g = this.canvas.getContext("2d");
this.g.scale(this.scaleFactor, this.scaleFactor);
//Однако теперь каждое выводимое значение надо будет масштабировать scaleFactor'ом
this.g.lineCap="round"; //Круглые изгибы стыков линий
this.g.textBaseline="middle";
this.width = this.canvas.width; //Ширина холста
this.height = this.canvas.height; //Высота холста
this.padding = 100; //Отступы
this.zero_x = this.padding; //Ноль графический X
this.zero_y = this.height-this.padding; //Ноль графический Y
this.canvas_x_min = this.padding; //Графический минимум Х
this.canvas_x_max = this.padding + this.width; //Графический максимум Х
this.canvas_y_min = this.height - this.padding; //Граф мин Y
this.canvas_y_max = this.padding;//Граф макс Y
this.k_x;//Коэфф на которые надо умножить чтобы
this.k_y;//привести данные к системе координат холста
this.data_x_min; //Минимальное значение данных по оси Х
this.data_x_max; //Макс знач данных Х
this.data_y_min; //Мин знач данных Y
this.data_y_max;//Макс знач данных Y
this.data_x_min = this.data[0].minX;
this.data_x_max = this.data[0].maxX;
this.data_y_min = this.data[0].minY;
this.data_y_max = this.data[0].maxY;
//Понадобится для быстрых проверок и интерактивности
this.view = [];
this.view.data = [];
//Ищем мимакс значения среди всех данных
for (var i=0;i<this.data.length;i++) {
if (this.data_x_min>this.data[i].minX) this.data_x_min = this.data[i].minX;
if (this.data_x_max<this.data[i].maxX) this.data_x_max = this.data[i].maxX;
if (this.data_y_min>this.data[i].minY) this.data_y_min = this.data[i].minY;
if (this.data_y_max<this.data[i].maxY) this.data_y_max = this.data[i].maxY;
//Присваеваем случайный цвет каждой серии
var color = "#"+(Math.random()*999999).toFixed(0).toString(16);
console.log(color);
this.data[i].color = color;
//Эти свойства понадобится впоследствии для интерактивности
this.view.data[i] = {};
this.view.data[i].highlighted = false;
this.view.data[i].points = [];
for (var j=0;j<this.data[i].timestamp.length;j++) {
this.view.data[i].points[j] = [];
}
}
//Вычисляем коэффициенты для приведения к системе координат холста
if (this.data_x_min!=this.data_x_max) {
this.k_x = (this.canvas_x_max-this.canvas_x_min)/(this.data_x_max-this.data_x_min);
} else { //Чтобы не получилось деления на ноль
this.k_x = (this.canvas_x_max-this.canvas_x_min)/(this.data_x_max);
}
if (this.data_y_min!=this.data_y_max) {
this.k_y = (this.canvas_y_min-this.canvas_y_max)/(this.data_y_max-this.data_y_min);
} else { //Чтобы не получилось деления на ноль
this.k_y = (this.canvas_y_min-this.canvas_y_max)/(this.data_y_max);
}
/**
*
* ЭТОТ МЕТОД НОРМАЛЬНО РИСУЕТ ГРАФИК
*
**/
//Объявляем метод
this.prototype.repaint = function(args) {
//Чертим ось Y
this.g.lineWidth = 2;
this.g.strokeStyle="#000000";
this.g.beginPath();
this.g.moveTo(this.zero_x/this.scaleFactor,this.zero_y/this.scaleFactor);
this.g.lineTo(this.zero_x/this.scaleFactor,this.padding/this.scaleFactor);
this.g.closePath();
this.g.stroke();
//Чертим ось X
this.g.beginPath();
this.g.moveTo(this.zero_x/this.scaleFactor,this.zero_y/this.scaleFactor);
this.g.lineTo((this.width-this.padding)/this.scaleFactor,this.zero_y/this.scaleFactor);
this.g.closePath();
this.g.stroke();
this.g.lineWidth = 0.5;
//Текст на оси Y
var gFontArgs = this.g.font.split(" "); //"?px %fontName%"
var newSize = "4px";
this.g.font = newSize+" "+gFontArgs[gFontArgs.length-1];//"12px %fontName%"
this.g.fillText(this.data_y_max,0,(this.zero_y - (this.data_y_max-this.data_y_min)*this.k_y)/this.scaleFactor); //MAX
this.g.fillText(this.data_y_min,0,this.zero_y/this.scaleFactor); //MIN
//Текст на оси Х
this.g.save();
this.g.translate(this.zero_x/this.scaleFactor, this.zero_y/this.scaleFactor);
this.g.rotate(-Math.PI/2);
var ddd = new Date(this.data_x_max);
this.g.fillText(ddd.toLocaleTimeString(), 0, this.curX/this.scaleFactor);
this.g.restore();
//Содержимое графика
for(var i=0;i<this.data.length;i++) {
this.g.strokeStyle=this.data[i].color;
//Выделяем серию, на которую наведена мышь
if (this.view.data[i].highlighted) {
this.g.lineWidth = 5;
this.view.data[i].highlighted = false;
} else {
this.g.lineWidth = 1;
}
for (var j=0;j<this.data[i].timestamp.length-1;j++) {
var curX = this.zero_x + (this.data[i].timestamp[j]-this.data_x_min) * this.k_x;
var curY = this.zero_y - (this.data[i].values[j]-this.data_y_min) * this.k_y;
var nextX = this.zero_x + (this.data[i].timestamp[j+1]-this.data_x_min) * this.k_x;
var nextY = this.zero_y - (this.data[i].values[j+1]-this.data_y_min) * this.k_y;
//Линии
this.g.beginPath();
this.g.moveTo(curX/this.scaleFactor,curY/this.scaleFactor);
this.g.lineTo(nextX/this.scaleFactor,nextY/this.scaleFactor);
//Сохраняем точки для последующего взаимодействия
this.view.data[i].points[j] = {};
this.view.data[i].points[j] = { x: curX/this.scaleFactor,
y: curY/this.scaleFactor};
this.g.closePath();
this.g.stroke();
}
}
}
/**
*
* ЭТОТ МЕТОД НЕ МОЖЕТ ПОЛУЧИТЬ ДОСТУП К СВОЙСТВАМ ОБЪЕКТА
*
*
*
* **/
//Объявляем метод
this.prototype.onMouseMove = function(event) {
var x = event.clientX*this.scalefactor/this.k_x-this.zero_x+this.data_min_x; //уже NaN
var y = this.zero_y - event.clientY*this.scalefactor/this.k_y-this.data_min_y; //уже NaN
for (var i=0;i<this.data.length;i++) // TYPE ERROR this.data IS UNDEFINED
for (var j=0;j<this.data[i].length;j++) {
if (this.view.data[i].points[j].x==x && this.view.data[i].points[j].y==y) {
this.model.data[i].highlighted = true;
}
}
}
};
};
var req = new XMLHttpRequest();
var ajaxURL = "http://localhost:8080/economiq1/ChartAJAX";
var params = "date=2016-01-25";
req.open("POST", ajaxURL, true);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.setRequestHeader("Content-length", params.length);
req.setRequestHeader("Connection", "close");
req.send(params);
req.onreadystatechange = function () {
if (req.readyState == 4 & req.status == 200) {
var chartData = JSON.parse(req.responseText);
var chart = new Chart(chartData);
chart.repaint();
}
}