/*global EventProxy, d3, Raphael, $ */ define(function (require, exports, module) { var DataV = require('datav'); var theme = DataV.Themes; var Matrix = DataV.extend(DataV.Chart, { initialize: function (container, options) { this.type = "Matrix"; this.container = container; this.defaults = {}; // Properties this.font = {}; // Canvas this.defaults.width = 1200; this.defaults.height = 1200; this.defaults.axisWidth = 40; this.setOptions(options); this.emitter = new EventProxy(); this.createCanvas(); this.move = false; } }); Matrix.prototype.on = function (eventName, callback) { this.emitter.on(eventName, callback); }; Matrix.prototype.setOptions = function (options) { var prop; if (options) { for (prop in options) { if (options.hasOwnProperty(prop)) { this.defaults[prop] = options[prop]; } } } }; Matrix.prototype.getDataTable = function (table) { var title = table[0]; table = table.slice(1); var titleLength = title.length; var tableWidth = table[0].length; var tableHeight = table.length; this.tableWidth = tableWidth; this.tableHeight = tableHeight; //for symmetric matrix if (tableWidth !== title.length || tableHeight !== title.length) { throw new Error("This matrix is not symmetric matrix!!!"); } else { this.tableWidth = tableWidth; this.tableHeight = tableHeight; } this.title = title; return table; }; Matrix.prototype.setSource = function (source) { var conf = this.defaults; this.source = this.getDataTable(source); this.hasSort = false; // this.source = this.remapSource(source); }; // Matrix.prototype.remapSource = function (data) { // return this.getDataTable(data); // // return data; // }; Matrix.prototype.layout = function () { var conf = this.defaults; var width = conf.width; var height = conf.height; var tableWidth = this.tableWidth; var tableHeight = this.tableHeight; var axisWidth = conf.axisWidth; this.cellWidth = Math.min((width - axisWidth) / tableWidth, (height - axisWidth) / tableHeight); var startX; var startY; var bRectWidth; var matrixWidth; if (width > height) { startX = (width - height)/2 + axisWidth; startY = axisWidth; bRectWidth = height - axisWidth; matrixWidth = bRectWidth - axisWidth; } else if (height > width) { startX = axisWidth; startY = (height - width) + axisWidth; bRectWidth = width - axisWidth; } else { startX = axisWidth; startY = axisWidth; bRectWidth = width - axisWidth; matrixWidth = bRectWidth - axisWidth; } this.startX = startX; this.startY = startY; this.bRectWidth = bRectWidth; this.matrixWidth = matrixWidth; }; Matrix.prototype.getColor = function (i) { var colorMatrix = DataV.getColor(); var length = colorMatrix.length; var num = i % length; //var color = '#939598'; var color = '#FFFFFF' if (num !== 0) { color = colorMatrix[num][0]; } return color; }; Matrix.prototype.createCanvas = function () { var conf = this.defaults; this.canvas = new Raphael(this.container, conf.width, conf.height); this.DOMNode = $(this.canvas.canvas); var that = this; this.DOMNode.click(function (event) { that.emitter.trigger("click", event); that.update(); }); this.DOMNode.dblclick(function (event) { that.emitter.trigger("dblclick", event); }); var mousewheel = document.all ? "mousewheel" : "DOMMouseScroll"; this.DOMNode.bind(mousewheel, function (event) { that.emitter.trigger("mousewheel", event); }); this.DOMNode.bind("contextmenu", function (event) { that.emitter.trigger("contextmenu", event); }); this.DOMNode.delegate("circle", "click", function (event) { that.emitter.trigger("circle_click", event); }); this.DOMNode.delegate("circle", "mouseover", function (event) { that.emitter.trigger("circle_mouseover", event); }); this.DOMNode.delegate("circle", "mouseout", function (event) { that.emitter.trigger("circle_mouseout", event); }); }; Matrix.prototype.generatePaths = function () { var canvas = this.canvas; var source = this.source; var conf = this.defaults; var width = conf.width; var height = conf.height; var startX = this.startX; var startY = this.startY; var cellWidth = this.cellWidth; var tableWidth = this.tableWidth; var tableHeight = this.tableHeight; var bRectWidth = this.bRectWidth; var matrixWidth = this.matrixWidth; //canvas.clear(); // var color = this.getColor(); // var font = this.getFont(); var font_family = '微软雅黑'; var font_size = 8; var title = this.title; var row = []; var columnLine = []; var columnText = []; var backgroundRect = canvas.rect(startX, startY, bRectWidth, bRectWidth); //backgroundRect.attr({fill: "#939598", stroke: "none", "fill-opacity": 0.8}); backgroundRect.attr({fill: "#ffffff", stroke: "none", "fill-opacity": 0.8}); backgroundRect.toBack(); var sort; if (this.hasSort) { sort = this.sort; } var i, j, a, b, color, rect; var rects = []; //for column change move rect for (i = 0; i < tableHeight; i++) { if (!this.hasSort){ a = i; } else { for (j = 0; j < sort.length; j++) { if (sort[j] === i) { a = j; } } } var rowRect = canvas.set(); //rowRect.push(canvas.path("M0 0L" + width + " 0").attr({stroke: "#ffffff"})); canvas.path("M" + startX + " " + (startY + cellWidth * i) + "L" + (startX + matrixWidth + 10 + cellWidth) + " " + (startY + cellWidth * i)).attr({stroke: "#D1D1D1", "stroke-width": 1}); rowRect.push(canvas.text(-20, cellWidth / 2, title[i]) .attr({"fill": "#000000", "fill-opacity": 0.7, "font-family": "Verdana", //"font-weight": "bold", "font-size": 12})); for (j = 0; j < tableWidth; j++) { if (!this.hasSort){ color = this.getColor(source[i][j]); } else { color = this.getColor(source[i][sort[j]]); } rect = canvas.rect(cellWidth * j, 0, cellWidth, cellWidth) .attr({stroke: "none", fill: color, "fill-opacity": 0.8}); rowRect.push(rect); rects.push(rect); } rowRect.transform("t" + startX + ", " + (startY + cellWidth * a)); row.push(rowRect); } canvas.path("M" + startX + " " + (startY + cellWidth * tableHeight) + "L" + (startX + matrixWidth + 10 + cellWidth) + " " + (startY + cellWidth * tableHeight)).attr({stroke: "#D1D1D1", "stroke-width": 1}); for (i = 0; i < tableWidth; i++) { // var columnLine = canvas.set(); // var columnText = canvas.set(); if (!this.hasSort){ a = i; } else { for (j = 0; j < sort.length; j++) { if (sort[j] === i) { a = j; } } } columnLine.push(canvas.path("M0 0L0 " + matrixWidth + 10 + cellWidth) .attr({stroke: "#D1D1D1", "stroke-width": 1}) .transform("t" + (startX + cellWidth * a) + ", " + startY)); columnText.push(canvas.text(cellWidth / 2, -20, title[i]) .attr({"fill": "#000000", "fill-opacity": 0.7, "font-family": "Verdana", //"font-weight": "bold", "font-size": 12}) .transform("t" + (startX + cellWidth * a) + ", " + startY + "r90")); // for (j = i * (tableWidth - 1); j < (i + 1) * (tableWidth - 1); j++){ // columnRect.push(rects[j]); // } //columnRect.transform("t" + (startX + cellWidth * i) + ", " + startY); // column.push(columnRect); } columnLine.push(canvas.path("M0 0L0 " + matrixWidth + 10 + cellWidth) .attr({stroke: "#D1D1D1", "stroke-width": 1}) .transform("t" + (startX + cellWidth * tableWidth) + ", " + startY)); this.row = row; this.columnText = columnText; this.columnLine = columnLine; this.rects = rects; }; Matrix.prototype.getSort = function (source) { var sumQueue = []; var sort = []; var rowData; var rowLength; var sum; var means; var matrixD = []; var quareSum; var rowquareSum = []; var i, j, k; for (i = 0 ; i < source.length ; i++) { rowData = source[i]; rowLength = rowData.length; sum = 0; quareSum = 0; for (j = 0 ; j < rowLength ; j++) { sum = sum + rowData[j]; } means = sum / rowLength; for (j = 0 ; j < rowLength ; j++) { rowData[j] = rowData[j] - means; quareSum = quareSum + Math.pow(rowData[j], 2); } quareSum = Math.sqrt(quareSum); rowquareSum.push(quareSum); matrixD.push(rowData); } var rowI; var rowJ; var matrixR = []; for (i = 0 ; i < source.length ; i++) { matrixR[i] = []; for (j = 0 ; j < source.length ; j++) { matrixR[i][j] = 0; } } for (i = 0 ; i < source.length ; i++) { rowI = matrixD[i]; matrixR[i][i] = source[i][i]; for (j = i + 1 ; j < source.length ; j++) { sum = 0; rowJ = matrixD[j]; for (k = 0; k < rowLength; k++) { sum = sum + rowI[k] * rowJ[k]; } sum = sum / (rowquareSum[i] * rowquareSum[j]); matrixR[i][j] = sum; matrixR[j][i] = sum; } } return matrixR; } Matrix.prototype.update = function () { var i, j; var source = []; for(i = 0; i < this.source.length ; i++){ source[i] = this.source[i].concat(); } var sort = []; for (i = 0; i < source[0].length; i++) { sort.push(i); } if (this.hasSort) { this.sort = sort; this.hasSort = false; } else { var getSort = this.getSort; var i, j; var pt; var nowSort = []; var iterations = 12; for (i = 0; i < iterations; i++) { source = getSort(source); } nowSort = source[0]; var a, b; for (i = 1; i < sort.length; i++) { a = sort[i]; for (j = i + 1; j < sort.length; j++) { b = sort[j]; if (nowSort[a] < nowSort[b]) { pt = sort[i]; sort[i] = sort[j]; sort[j] = pt; } } } sort = [0,7,5,2,8,3,1,9,6,14,15,4,13,10,16,11,12]; this.sort = sort; this.hasSort = true; } if (!this.move) { this.move = true; var rects = this.rects; var num; var startX = this.startX; var startY = this.startY; var cellWidth = this.cellWidth; var rowAnim; var columnLineAnim; var columnTextAnim; var anim; for (i = 0; i < sort.length; i++) { num = sort[i]; // if (num != i) { rowAnim = Raphael.animation({transform: ["t", startX, (startY + cellWidth * i)]}, 200, "<>"); this.row[num].animate(rowAnim.delay(100 * i)); // } } var that = this; var moveEnd = function () { that.move = false; }; for (i = 0; i < sort.length; i++) { num = sort[i]; // if (num != i) { //columnLineAnim = Raphael.animation({transform: ["t", (startX + cellWidth * i), startY]}, 1000, "<>"); columnTextAnim = Raphael.animation({transform: ["t", (startX + cellWidth * i), startY, "r", 90]}, 200, "<>"); //this.columnLine[num].animate(columnLineAnim.delay(500 * (i + sort.length + 1))); this.columnText[num].animate(columnTextAnim.delay(100 * (i + sort.length + 1))); for (j = 0; j < sort.length; j++) { if (i === sort.length - 1 && j === sort.length - 1) { anim = Raphael.animation({'x': cellWidth * i}, 200, "<>", moveEnd); } else { anim = Raphael.animation({'x': cellWidth * i}, 200, "<>"); } rects[j * sort.length + num].animate(anim.delay(100 * (i + sort.length + 1))); } // } } } }; Matrix.prototype.render = function (options) { if (!this.container) { throw new Error("Please specify which node to render."); } if (!this.move) { this.canvas.clear(); this.setOptions(options); this.layout(); this.generatePaths(); } //this.canvas.renderfix(); }; module.exports = Matrix; });