// helper function from github.com/usfvgl/defaults-centroid/ function getClassCentroid(data, selectedclass, xDomain, yDomain){ var classData = data.filter(function(d){ return d.class == selectedclass; }); var xAvg = d3.mean(classData, function(d) {return d[xDomain]}) var yAvg = d3.mean(classData, function(d) {return d[yDomain]}) centroid = {"xAvg": xAvg, "yAvg": yAvg, "class": selectedclass} return centroid; } function getDist (x1, y1, x2, y2) { var x = x2 - x1 var y = y2 - y1 return Math.sqrt(((x*x) + (y*y))) } // helper function to shuffle array //https://javascript.info/task/shuffle function shuffleZ(o) { for (var i = o.z.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); [o.z[i], o.z[j]] = [o.z[j], o.z[i]]; [o.z2[i], o.z2[j]] = [o.z2[j], o.z2[i]]; } } // main function to generate a training chart function chart() { var sample = false var min = 0 var max = 10 var colorScheme = 0; // default color scheme from color brewer var colorNames = { "rgb(27,158,119)": "green", "rgb(217,95,2)": "orange", "rgb(117,112,179)": "purple", "rgb(231,41,138)": "pink" } var colorSchemes = [ { z: ["rgb(228,26,28)", "rgb(55,126,184)", "rgb(77,175,74)", "rgb(152,78,163)", "rgb(255,127,0)", "rgb(255,255,51)"], z2: ["rgba(228,26,28, 0.5)", "rgba(55,126,184, 0.5)", "rgba(77,175,74, 0.5)", "rgba(152,78,163, 0.5)", "rgba(255,127,0, 0.5)", "rgba(255,255,51, 0.5)"] }, { z: ["rgb(127,201,127)", "rgb(190,174,212)", "rgb(253,192,134)", "rgb(255,255,153)", "rgb(56,108,176)", "rgb(240,2,127)"], z2: ["rgba(127,201,127, 0.5)", "rgba(190,174,212, 0.5)", "rgba(253,192,134, 0.5)", "rgba(255,255,153, 0.5)", "rgba(56,108,176, 0.5)", "rgba(240,2,127)"] }, { z: ["rgb(27,158,119)", "rgb(217,95,2)", "rgb(117,112,179)", "rgb(231,41,138)"], z2: ["rgba(27,158,119, 0.5)", "rgba(217,95,2, 0.5)", "rgba(117,112,179, 0.5)", "rgba(231,41,138, 0.5)"] }, { z: ["rgb(255,115,75)", "rgb(191,84,122)", "rgb(131,148,77)", "rgb(255,238,56)", "rgb(152,123,104)", "rbg(255,174,0)"], z2: ["rgba(255,115,75, 0.5)", "rgba(191,84,122, 0.5)", "rgba(131,148,77, 0.5)", "rgba(255,238,56, 0.5)", "rgb(152,123,104, 0.5)", "rbga(255,174,0, 0.5)"] }, { z: ["rgb(178,91,122)", "rgb(135,147,86)", "rgb(240,142,86)", "rgb(253,237,95)"], z2: ["rgba(178,91,122, 0.5)", "rgba(135,147,86, 0.5)", "rgba(240,142,86, 0.5)", "rgba(253,237,95, 0.5)"] }, { z: ["rgb(178,91,122)", "rgb(135,147,86)", "rgb(240,142,86)", "rgb(253,237,95)", "rgb(83,71,58)", "rbg(239,101,77)"], z2: ["rgba(178,91,122, 0.5)", "rgba(135,147,86, 0.5)", "rgba(240,142,86, 0.5)", "rgba(253,237,95, 0.5)", "rgb(83,71,58, 0.5)", "rbga(239,101,77, 0.5)"] } ] var centroid_clicked = false; var isMouseDown = false; var isFaded = false, startX, startY, dragX, dragY, tutorial = false, timer, circle_on, selectedClass, width, height, centroids = {}, radius = 35, // size of point radiusWidth = 3, //width of open circle stroke xDomain = "carat", yDomain = "price", zDomain = "cut", autoPlay = false, playing = false, currentI = 0, rpw = 10, //rows per second to animate loop, pause, datasetSize, drawPoints, drawAnimationProgress, play, drawData = { color: {}, point : { solid: true, opencircle: false, alpha: false }, buffers: { solid: {}, opencircle: {}, alpha: {} }, alpha: 0.3 }; var centroid_circles = []; var margin = {top: 30, right: 20, bottom: 180, left: 20}; var canvasWidth = 900; var canvasHeight = 500; width = 900 - margin.right - margin.left, // default width height = 500 - margin.top - margin.bottom; // default height var blending_modes = { "source-over": true, "multiply": false, "screen": false, "overlay": false, "darken": false, "lighten": false, "color-dodge": false, "color-burn": false, "hard-light": false, "soft-light": false, "difference": false, "exclusion": false, "hue": false, "saturation": false, "color": false, "luminosity": false } function my(selection) { my.clicks = 0; my.startTime = null; my.endTime = null; selection.each(function(data) { //scales var x = d3.scaleLinear().range([margin.left, width]); var y = d3.scaleLinear().range([height, margin.top]); shuffleZ(colorSchemes[colorScheme]) var z = d3.scaleOrdinal(colorSchemes[colorScheme].z); var z2 = d3.scaleOrdinal(colorSchemes[colorScheme].z2); var legendX = d3.scaleLinear().rangeRound([0, margin.right - 70]); var progressX = d3.scaleLinear().range([0, 2*Math.PI]); //generate chart; var root = this; canvas = root.appendChild(document.createElement("canvas")), context = canvas.getContext("2d"); canvas.id = "chart-canvas" canvas.width = canvasWidth; canvas.height = canvasHeight; events_canvas = root.appendChild(document.createElement("canvas")); econtext = events_canvas.getContext("2d"); events_canvas.id = "events-canvas"; events_canvas.width = canvasWidth; events_canvas.height = canvasHeight; // generate controls var node = document.createElement("div"); var visual_controls_node = document.createElement("form"); var visual_controls = root.appendChild(visual_controls_node); //point functions var point = d3.symbol() .size(radius) .context(context); var openpoint = d3.symbol() .size(radius + radiusWidth) .context(context); var openpoint_stroke = d3.symbol() .size(radius + radiusWidth + radiusWidth) .context(context); var animation_circle = d3.symbol() .size(750) .context(context); function drawPoint (d) { //draw point in context var selectedPoint = getSelectedPointType(); context.translate(d.x, d.y); if (selectedPoint === "solid") { context.fillStyle = z(d[zDomain]); context.strokeStyle = "white"; context.beginPath(); point(d); context.closePath(); context.fill(); context.stroke(); } else if (selectedPoint === "opencircle") { context.strokeStyle = "white" context.lineWidth = 2.5; context.beginPath(); openpoint_stroke(d); context.closePath(); context.stroke(); context.strokeStyle = z(d[zDomain]); context.lineWidth = 1; context.beginPath(); openpoint(d); context.closePath(); context.stroke(); } else if (selectedPoint === "alpha") { context.fillStyle = z(d[zDomain]) context.globalAlpha = drawData.alpha; context.beginPath(); point(d); context.closePath(); context.fill(); context.globalAlpha = 1.0; } context.translate(-d.x, -d.y); } // setup context.translate(margin.left, margin.top); context.font = "12px sans-serif"; x.domain([min,max]); y.domain([min,max]); z.domain(d3.map(data, function(d){return d[zDomain];}).keys()); progressX.domain([0, data.length]); datasetSize = data.length; z.domain().forEach(function (d, i){ //set initial values for