Last active
March 3, 2018 18:06
-
-
Save homerhanumat/4f315ccae8707b64236500da7e35810a to your computer and use it in GitHub Desktop.
R^2 Illustration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| license: MIT | |
| height: 1000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <html> | |
| <head> | |
| <style> | |
| body { | |
| margin: 0 auto; | |
| margin-top: 1em; | |
| display: table; | |
| font-family: "Helvetica Neue", sans-serif; | |
| } | |
| button { | |
| position: relative; | |
| top: 0; | |
| border: solid red 2px; | |
| border-radius: 3px; | |
| box-shadow: 0px 4px rgba(82, 29, 29, 0.2); | |
| margin: 0 7px 11px 0; | |
| } | |
| button:hover { | |
| background-color: burlywood; | |
| box-shadow: 0px 3px rgba(22, 4, 4, 0.2); | |
| } | |
| button:active { | |
| top: 2px; | |
| ; | |
| } | |
| svg { | |
| padding-bottom: 16px; | |
| } | |
| .groupMean { | |
| stroke-width: 2px; | |
| stroke: rgb(90, 90, 206); | |
| cursor: none; | |
| pointer-events: none; | |
| } | |
| .groupMeanUse { | |
| stroke: transparent; | |
| stroke-width: 16px; | |
| z-index: 99; | |
| } | |
| .groupMeanUse.active { | |
| cursor: move; | |
| pointer-events: all; | |
| } | |
| .inactive { | |
| visibility: hidden; | |
| cursor: none; | |
| pointer-events: none; | |
| } | |
| .groupYbar { | |
| stroke-width: 2px; | |
| stroke: red; | |
| stroke-dasharray: 10, 5; | |
| cursor: none; | |
| pointer-events: none; | |
| } | |
| .ybb { | |
| stroke-width: 3px; | |
| stroke: red; | |
| stroke-dasharray: 10, 5; | |
| cursor: none; | |
| pointer-events: none; | |
| } | |
| .point { | |
| cursor: none; | |
| pointer-events: none; | |
| } | |
| .vertical { | |
| stroke-width: 1px; | |
| stroke: darkgreen; | |
| } | |
| .axistext { | |
| font-size: 14px; | |
| } | |
| #selector { | |
| margin-left: 50px; | |
| } | |
| .meanpoint { | |
| visibility: hidden; | |
| } | |
| .report span { | |
| width: 50px; | |
| padding-right: 1.5em; | |
| } | |
| #sigmaValue { | |
| display: block; | |
| font-size: 1.2em; | |
| font-weight: bold; | |
| text-align: center; | |
| margin: 15px 0; | |
| width: 100%; | |
| } | |
| .info { | |
| max-width: 600px; | |
| } | |
| </style> | |
| <link rel="stylesheet" type="text/css" href="range-slider-flat.css"> | |
| </head> | |
| <body> | |
| <div> | |
| <button id="resample" name="button">Resample</button> | |
| <button id="sse" name="button">Error SS</button> | |
| <button id="ssm" name="button">Treatment SS</button> | |
| <button id="sst" name="button">Total SS</button> | |
| <button id="groupMeans" name="button">Group Means</button> | |
| </div> | |
| <div> | |
| <input id="sigma" type="range" min="0" max="5" step="0.1" data-rangeSlider /> | |
| <ouput id="sigmavalue"> | |
| </output> | |
| </div> | |
| <div class="chart"></div> | |
| <p=c lass="report"> | |
| <span>Error SS: | |
| <output id="sse-value"></output> | |
| </span> | |
| <span>Treatment SS: | |
| <output id="ssm-value"></output> | |
| </span> | |
| </p> | |
| <p class="report"> | |
| <span>Total SS: | |
| <output id="sst-value"></output> | |
| </span> | |
| <span>R^2: | |
| <output id="r2-value"></output> | |
| </span> | |
| </p> | |
| <p class = "info">Blue lines represent the population mean for each group. | |
| Dotted green lines are the sample means. Drag a blue line | |
| to change the population mean. The slider controls the | |
| standard devition of the group populations. | |
| </p> | |
| <script src="range-slider.min.js"></script> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <script> | |
| const width = 500, | |
| height = 500; | |
| const margin = { top: 33, right: 5, bottom: 35, left: 50 }, | |
| innerWidth = width - margin.left - margin.right, | |
| innerHeight = width - margin.top - margin.bottom; | |
| const n = 10; | |
| // number of groups (limit 12, please) | |
| const groupNumber = 3; | |
| const groups = "abcdefghijkl".split("").slice(0, groupNumber); | |
| const minY = 0, maxY = 40; | |
| const minAllowedGroupMean = 10; | |
| const maxAllowedGroupMean = 30; | |
| let groupMeans = Array(groupNumber).fill(20); | |
| const maxSigma = 5; | |
| let sigma = 2.5; | |
| // set up x-scale now | |
| const x = d3.scaleBand() | |
| .range([0, innerWidth]); | |
| x.domain(groups); | |
| const data = generateData(x, groups, groupMeans, n, sigma); | |
| const [sse, ssm, sst, r2] = sumSquares(data); | |
| document.querySelector("#sse-value").innerHTML = precisionRound(sse, 2); | |
| document.querySelector("#ssm-value").innerHTML = precisionRound(ssm, 2); | |
| document.querySelector("#sst-value").innerHTML = precisionRound(sst, 2); | |
| document.querySelector("#r2-value").innerHTML = precisionRound(r2, 4); | |
| document.querySelector("#resample") | |
| .addEventListener("click", resampleHandler); | |
| document.querySelector("#sigma") | |
| .addEventListener("input", sigmaHandler); | |
| document.querySelector("#sse") | |
| .addEventListener("click", sseHandler); | |
| document.querySelector("#ssm") | |
| .addEventListener("click", ssmHandler); | |
| document.querySelector("#sst") | |
| .addEventListener("click", sstHandler); | |
| document.querySelector("#groupMeans") | |
| .addEventListener("click", groupMeansHandler); | |
| const svg = d3.select(".chart") | |
| .append("svg") | |
| .attr("width", innerWidth + margin.left + margin.right) | |
| .attr("height", innerHeight + margin.top + margin.bottom); | |
| const svgInside = svg.append("g") | |
| .attr("transform", `translate(${margin.left},${margin.top})`) | |
| .classed("innersvg", true); | |
| const y = d3.scaleLinear() | |
| .range([innerHeight, 0]); | |
| const xAxis = d3.axisBottom() | |
| .scale(x); | |
| const yAxis = d3.axisLeft() | |
| .scale(y); | |
| const yaxistext = "y"; | |
| svgInside.append("text") | |
| .attr("class", "axistext") | |
| .attr("transform", "rotate(-90)") | |
| .attr("y", 0 - margin.left) | |
| .attr("x", 0 - (innerHeight / 2)) | |
| .attr("dy", "1em") | |
| .style("text-anchor", "middle") | |
| .text(yaxistext); | |
| const [minMean, maxMean] = d3.extent(groupMeans); | |
| y.domain([minY, maxY]); | |
| svgInside.append("g") | |
| .attr("class", "x axis") | |
| .attr("transform", `translate(0,${innerHeight})`) | |
| .call(xAxis); | |
| svgInside.append("g") | |
| .attr("class", "y axis") | |
| .call(yAxis); | |
| drawAll(data); | |
| document.querySelector("#sigmavalue") | |
| .innerHTML = `Sigma: ${sigma}`; | |
| document.querySelector("#sigma").value = sigma.toFixed(1); | |
| // FUNCTIONS ......................................................... | |
| function gaussian(a, b) { | |
| return { | |
| u: Math.sqrt(-2 * Math.log(a)) * Math.cos(2 * Math.PI * b), | |
| v: Math.sqrt(-2 * Math.log(a)) * Math.sin(2 * Math.PI * b) | |
| }; | |
| } | |
| function gaussianArray(n, mu, sigma) { | |
| let data = []; | |
| while (data.length < n) { | |
| let u1 = Math.random(); | |
| let u2 = Math.random(); | |
| let { u, v } = gaussian(u1, u2); | |
| let x = mu + sigma * u; | |
| let y = mu + sigma * v; | |
| data.push(x); | |
| if (data.length < n) data.push(y); | |
| } | |
| return data; | |
| } | |
| function meanOfAll(data) { | |
| let allYs = []; | |
| data.forEach(group => { | |
| allYs = allYs.concat(group.yvals); | |
| }); | |
| return d3.mean(allYs); | |
| } | |
| function sumSquares(data) { | |
| let SSM = 0, SST = 0; | |
| let allYs = []; | |
| data.forEach(group => { | |
| allYs = allYs.concat(group.yvals); | |
| }); | |
| const ybb = d3.mean(allYs); | |
| //SST = allYs.reduce((acc, y) => acc + (y - ybb) * (y - ybb)); | |
| for (let i = 0; i < n * data.length; i++) { | |
| SST += (allYs[i] - ybb) * (allYs[i] - ybb); | |
| } | |
| for (let i = 0; i < data.length; i++) { | |
| let groupMean = d3.mean(data[i].yvals); | |
| SSM += (n * (groupMean - ybb) * (groupMean - ybb)); | |
| } | |
| const SSE = SST - SSM; | |
| const R2 = SSM / SST | |
| return [SSE, SSM, SST, R2]; | |
| } | |
| function precisionRound(number, precision) { | |
| const factor = Math.pow(10, precision); | |
| return Math.round(number * factor) / factor; | |
| } | |
| function generateData(x, groups, groupMeans, n, sigma) { | |
| const spacing = x(groups[1]) - x(groups[0]); | |
| const padding = spacing / 8; | |
| let data = []; | |
| for (let i = 0; i < groups.length; i++) { | |
| const start = x(groups[i]) + padding; | |
| const end = x(groups[i]) + spacing - padding; | |
| data.push({ | |
| group: groups[i], | |
| groupMean: groupMeans[i], | |
| start: start, | |
| end: end, | |
| xvals: spreadEvenly(n, start, end), | |
| yvals: gaussianArray(n, groupMeans[i], sigma) | |
| }); | |
| } | |
| return data; | |
| } | |
| function updateDataGroup(index) { | |
| const gm = data[index].groupMean; | |
| data[index].yvals = gaussianArray(n, gm, sigma); | |
| } | |
| function updateData() { | |
| for (let i = 0; i < data.length; i++) { | |
| updateDataGroup(i); | |
| } | |
| } | |
| function updateOutputs() { | |
| const [sse, ssm, sst, r2] = sumSquares(data); | |
| document.querySelector("#sse-value") | |
| .innerHTML = precisionRound(sse, 2); | |
| document.querySelector("#ssm-value") | |
| .innerHTML = precisionRound(ssm, 2); | |
| document.querySelector("#sst-value") | |
| .innerHTML = precisionRound(sst, 2); | |
| document.querySelector("#r2-value") | |
| .innerHTML = precisionRound(r2, 4); | |
| } | |
| function resampleHandler() { | |
| clearErrorLines(); | |
| clearTreatmentLines(); | |
| clearTotalLines(); | |
| updateData(); | |
| updateOutputs(); | |
| drawAll(data); | |
| } | |
| function sigmaHandler() { | |
| clearErrorLines(); | |
| clearTreatmentLines(); | |
| clearTotalLines(); | |
| sigma = parseFloat(this.value); | |
| document.querySelector("#sigmavalue") | |
| .innerHTML = `Sigma: ${sigma.toFixed(1)}`; | |
| updateData(); | |
| updateOutputs(); | |
| drawAll(data); | |
| } | |
| function clearTreatmentLines() { | |
| svgInside.selectAll(".yb-ybb").remove() | |
| svgInside.select("#ybbLine").remove() | |
| svgInside.selectAll(".point") | |
| .style("opacity", 1); | |
| } | |
| function clearErrorLines() { | |
| svgInside.selectAll(".point-yb").remove() | |
| } | |
| function clearTotalLines() { | |
| svgInside.selectAll(".point-ybb").remove() | |
| svgInside.select("#ybbLine").remove() | |
| } | |
| function groupMeansHandler() { | |
| clearTreatmentLines(); | |
| clearTotalLines(); | |
| clearErrorLines(); | |
| svgInside.selectAll(".groupYbar") | |
| .classed("active", true) | |
| .classed("inactive", false); | |
| svgInside.selectAll(".groupMean") | |
| .classed("active", true) | |
| .classed("inactive", false); | |
| svgInside.selectAll(".groupMeanUse") | |
| .classed("active", true) | |
| .classed("inactive", false); | |
| } | |
| function sseHandler() { | |
| clearTreatmentLines(); | |
| clearTotalLines(); | |
| svgInside.selectAll(".groupYbar") | |
| .classed("active", true) | |
| .classed("inactive", false); | |
| svgInside.selectAll(".groupMeanUse") | |
| .classed("inactive", true); | |
| svgInside.selectAll(".groupMean") | |
| .classed("inactive", true); | |
| for (let i = 0; i < data.length; i++) { | |
| for (let j = 0; j < n; j++) { | |
| addErrorLine(i, j); | |
| } | |
| } | |
| } | |
| function ssmHandler() { | |
| clearErrorLines(); | |
| clearTotalLines(); | |
| svgInside.selectAll(".point") | |
| .style("opacity", 0.3); | |
| svgInside.selectAll(".groupYbar") | |
| .classed("active", true) | |
| .classed("inactive", false); | |
| svgInside.selectAll(".groupMeanUse") | |
| .classed("inactive", true); | |
| svgInside.selectAll(".groupMean") | |
| .classed("inactive", true); | |
| const ybb = meanOfAll(data); | |
| svgInside.append("line") | |
| .attr("id", "ybbLine") | |
| .attr("x1", data[0].start) | |
| .attr("x2", data[data.length - 1].end) | |
| .attr("y1", y(ybb)) | |
| .attr("y2", y(ybb)) | |
| .attr("stroke", "red") | |
| .attr("stroke-width", 3) | |
| ; | |
| for (let i = 0; i < data.length; i++) { | |
| for (let j = 0; j < n; j++) { | |
| addTreatmentLine(i, j); | |
| } | |
| } | |
| } | |
| function sstHandler() { | |
| clearErrorLines(); | |
| clearTreatmentLines(); | |
| svgInside.selectAll(".groupYbar") | |
| .classed("active", false) | |
| .classed("inactive", true); | |
| svgInside.selectAll(".groupMeanUse") | |
| .classed("inactive", true); | |
| svgInside.selectAll(".groupMean") | |
| .classed("inactive", true); | |
| const ybb = meanOfAll(data); | |
| svgInside.append("line") | |
| .attr("id", "ybbLine") | |
| .attr("x1", data[0].start) | |
| .attr("x2", data[data.length - 1].end) | |
| .attr("y1", y(ybb)) | |
| .attr("y2", y(ybb)) | |
| .attr("stroke", "red") | |
| .attr("stroke-width", 3) | |
| ; | |
| for (let i = 0; i < data.length; i++) { | |
| for (let j = 0; j < n; j++) { | |
| addTotalLine(i, j); | |
| } | |
| } | |
| } | |
| function addErrorLine(i, j) { | |
| svgInside.append("line") | |
| .attr("class", "vertical") | |
| .classed("point-yb", true) | |
| .attr("x1", data[i].xvals[j]) | |
| .attr("x2", data[i].xvals[j]) | |
| .attr("y1", y(data[i].yvals[j])) | |
| .attr("y2", y(d3.mean(data[i].yvals))) | |
| ; | |
| } | |
| function addTreatmentLine(i, j) { | |
| svgInside.append("line") | |
| .attr("class", "vertical") | |
| .classed("yb-ybb", true) | |
| .attr("x1", data[i].xvals[j]) | |
| .attr("x2", data[i].xvals[j]) | |
| .attr("y1", y(d3.mean(data[i].yvals))) | |
| .attr("y2", y(meanOfAll(data))) | |
| ; | |
| } | |
| function addTotalLine(i, j) { | |
| svgInside.append("line") | |
| .attr("class", "vertical") | |
| .classed("point-ybb", true) | |
| .attr("x1", data[i].xvals[j]) | |
| .attr("x2", data[i].xvals[j]) | |
| .attr("y1", y(data[i].yvals[j])) | |
| .attr("y2", y(meanOfAll(data))) | |
| ; | |
| } | |
| function spreadEvenly(n, a, b) { | |
| const step = (b - a) / (n + 1); | |
| let arr = []; | |
| for (let i = 0; i < n; i++) { | |
| arr.push(a + (i + 1) * step); | |
| } | |
| return arr; | |
| } | |
| function drawGroup(group) { | |
| const [dataGroup] = data.filter(elem => elem.group == group); | |
| drawInsideGroup(group); | |
| svgInside.selectAll(`[data-group=${group}]`).remove(); | |
| const groupMeanLine = svgInside.append("line") | |
| .attr("class", "groupMeanUse") | |
| .attr("id", `groupMeanUse-${group}`) | |
| .attr("data-group", dataGroup.group) | |
| .attr("x1", dataGroup.start) | |
| .attr("x2", dataGroup.end) | |
| .attr("y1", y(dataGroup.groupMean)) | |
| .attr("y2", y(dataGroup.groupMean)) | |
| ; | |
| drawInsideGroup(group); | |
| const dragHandler = d3.drag().on("drag", function () { | |
| const okToMove = y.invert(d3.event.y) >= minAllowedGroupMean && | |
| y.invert(d3.event.y) <= maxAllowedGroupMean; | |
| if (okToMove) { | |
| newGroupMean = y.invert(d3.event.y); | |
| const group = this.getAttribute("data-group"); | |
| const index = groups.indexOf(group); | |
| data[index].groupMean = newGroupMean; | |
| updateDataGroup(index); | |
| this.setAttribute("y1", y(dataGroup.groupMean)); | |
| this.setAttribute("y2", y(dataGroup.groupMean)); | |
| d3.select(`#groupMean-${group}`).remove(); | |
| drawInsideGroup(group); | |
| updateOutputs(); | |
| } | |
| }); | |
| dragHandler(groupMeanLine); | |
| } | |
| function drawInsideGroup(group) { | |
| const [dataGroup] = data.filter(elem => elem.group == group); | |
| const index = groups.indexOf(group); | |
| const groupMeanLine = svgInside.append("line") | |
| .attr("class", "groupMean") | |
| .attr("id", `groupMean-${group}`) | |
| .attr("data-group", dataGroup.group) | |
| .attr("x1", dataGroup.start) | |
| .attr("x2", dataGroup.end) | |
| .attr("y1", y(dataGroup.groupMean)) | |
| .attr("y2", y(dataGroup.groupMean)) | |
| ; | |
| svgInside.selectAll(`#groupYbarLine-${group}`) | |
| .remove() | |
| svgInside.append("line") | |
| .attr("class", "groupYbar") | |
| .attr("id", `groupYbarLine-${group}`) | |
| .attr("data-group", dataGroup.group) | |
| .attr("x1", dataGroup.start) | |
| .attr("x2", dataGroup.end) | |
| .attr("y1", y(d3.mean(dataGroup.yvals))) | |
| .attr("y2", y(d3.mean(dataGroup.yvals))) | |
| ; | |
| svgInside.selectAll(`.point[data-group=${group}]`) | |
| .remove() | |
| for (let j = 0; j < n; j++) { | |
| svgInside.append("circle") | |
| .attr("class", "point") | |
| .attr("data-group", dataGroup.group) | |
| .attr("r", 2) | |
| .attr("cx", dataGroup.xvals[j]) | |
| .attr("cy", y(dataGroup.yvals[j])) | |
| ; | |
| } | |
| } | |
| function drawAll(data) { | |
| for (let i = 0; i < groups.length; i++) { | |
| const group = data[i].group; | |
| drawGroup(group); | |
| } | |
| svgInside.selectAll(".groupMeanUse") | |
| .classed("active", true); | |
| } | |
| // Slider ............................................ | |
| const slider = document.querySelector('#sigma'); | |
| rangeSlider.create(slider, { | |
| polyfill: true, // | |
| rangeClass: 'rangeSlider', | |
| disabledClass: 'rangeSlider--disabled', | |
| fillClass: 'rangeSlider__fill', | |
| bufferClass: 'rangeSlider__buffer', | |
| handleClass: 'rangeSlider__handle', | |
| startEvent: ['mousedown', 'touchstart', 'pointerdown'], | |
| moveEvent: ['mousemove', 'touchmove', 'pointermove'], | |
| endEvent: ['mouseup', 'touchend', 'pointerup'], | |
| vertical: false, // Boolean, | |
| min: 0, // Number , 0 | |
| max: maxSigma, // Number, 100 | |
| step: 0.1, // Number, 1 | |
| value: sigma, // Number, center of slider | |
| buffer: null, // Number, in percent, 0 by default | |
| stick: null, // [Number stickTo, Number stickRadius] | |
| borderRadius: 10, // Number, | |
| onInit: function () { | |
| console.info('onInit') | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /************************************************ | |
| * Source: | |
| * https://github.com/Stryzhevskyi/rangeSlider | |
| * License: MIT | |
| *************************************************/ | |
| .rangeSlider, | |
| .rangeSlider__fill { | |
| background: #7f8c8d; | |
| display: block; | |
| height: 8px; | |
| width: 100%; | |
| -webkit-box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.3); | |
| -moz-box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.3); | |
| box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.5); | |
| -webkit-border-radius: 10px; | |
| -moz-border-radius: 10px; | |
| -ms-border-radius: 10px; | |
| -o-border-radius: 10px; | |
| border-radius: 4px; | |
| } | |
| .rangeSlider { | |
| position: relative; | |
| } | |
| .rangeSlider--disabled { | |
| filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40); | |
| opacity: 0.4; | |
| } | |
| .rangeSlider__fill { | |
| background: #FFFFFF; | |
| position: absolute; | |
| top: 0; | |
| z-index: 2; | |
| } | |
| .rangeSlider__handle { | |
| background: white; | |
| border: 1px solid #ccc; | |
| cursor: pointer; | |
| display: inline-block; | |
| width: 22px; | |
| height: 21px; | |
| position: absolute; | |
| top: -7px; | |
| z-index: 3; | |
| background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(100%, rgba(0, 0, 0, 0.1))); | |
| background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.1)); | |
| background-image: -moz-linear-gradient(rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.1)); | |
| background-image: -o-linear-gradient(rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.1)); | |
| background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.1)); | |
| -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.3); | |
| -moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.3); | |
| box-shadow: 0 0 4px rgba(0, 0, 0, 0.3); | |
| -webkit-border-radius: 50%; | |
| -moz-border-radius: 50%; | |
| -ms-border-radius: 50%; | |
| -o-border-radius: 50%; | |
| border-radius: 50%; | |
| } | |
| .rangeSlider__handle:after { | |
| content: ""; | |
| display: block; | |
| width: 10px; | |
| height: 10px; | |
| margin: auto; | |
| position: absolute; | |
| top: 0; | |
| right: 0; | |
| bottom: 0; | |
| left: 0; | |
| background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(0, 0, 0, 0.13)), color-stop(100%, rgba(255, 255, 255, 0))); | |
| background-image: -webkit-linear-gradient(rgba(0, 0, 0, 0.13), rgba(255, 255, 255, 0)); | |
| background-image: -moz-linear-gradient(rgba(0, 0, 0, 0.13), rgba(255, 255, 255, 0)); | |
| background-image: -o-linear-gradient(rgba(0, 0, 0, 0.13), rgba(255, 255, 255, 0)); | |
| background-image: linear-gradient(rgba(0, 0, 0, 0.13), rgba(255, 255, 255, 0)); | |
| -webkit-border-radius: 50%; | |
| -moz-border-radius: 50%; | |
| -ms-border-radius: 50%; | |
| -o-border-radius: 50%; | |
| border-radius: 50%; | |
| } | |
| .rangeSlider__handle:active { | |
| background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(0, 0, 0, 0.1)), color-stop(100%, rgba(0, 0, 0, 0.12))); | |
| background-image: -webkit-linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.12)); | |
| background-image: -moz-linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.12)); | |
| background-image: -o-linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.12)); | |
| background-image: linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.12)); | |
| outline: none; | |
| } | |
| input[type="range"]:focus + .rangeSlider .rangeSlider__handle { | |
| -webkit-box-shadow: 0 0 8px rgba(142, 68, 173, 0.9); | |
| -moz-box-shadow: 0 0 8px rgba(142, 68, 173, 0.9); | |
| box-shadow: 0 0 8px rgba(142, 68, 173, 0.9); | |
| } | |
| .rangeSlider__buffer { | |
| z-index: 1; | |
| position: absolute; | |
| top: 2px; | |
| height: 4px; | |
| background: #2c3e50; | |
| border-radius: 2px; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("rangeSlider",[],t):"object"==typeof exports?exports.rangeSlider=t():e.rangeSlider=t()}(this,function(){return function(e){function t(n){if(i[n])return i[n].exports;var s=i[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,t),s.l=!0,s.exports}var i={};return t.m=e,t.c=i,t.d=function(e,i,n){t.o(e,i)||Object.defineProperty(e,i,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var i=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(i,"a",i),i},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=1)}([function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=(t.delay=function(e,t){for(var i=arguments.length,n=Array(i>2?i-2:0),s=2;s<i;s++)n[s-2]=arguments[s];return setTimeout(function(){return e.apply(null,n)},t)},t.debounce=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:100;return function(){for(var i=arguments.length,n=Array(i),s=0;s<i;s++)n[s]=arguments[s];return e.debouncing||(e.lastReturnVal=e.apply(window,n),e.debouncing=!0),clearTimeout(e.debounceTimeout),e.debounceTimeout=setTimeout(function(){e.debouncing=!1},t),e.lastReturnVal}},t.isString=function(e){return e===""+e}),s=(t.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},t.isNumberLike=function(e){return null!==e&&void 0!==e&&(n(e)&&isFinite(parseFloat(e))||isFinite(e))});t.getFirsNumberLike=function(){for(var e=arguments.length,t=Array(e),i=0;i<e;i++)t[i]=arguments[i];if(!t.length)return null;for(var n=0,r=t.length;n<r;n++)if(s(t[n]))return t[n];return null},t.isObject=function(e){return"[object Object]"===Object.prototype.toString.call(e)},t.simpleExtend=function(e,t){var i={};for(var n in e)i[n]=e[n];for(var s in t)i[s]=t[s];return i},t.between=function(e,t,i){return e<t?t:e>i?i:e}},function(e,t,i){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t.default=e,t}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){for(var i=0;i<t.length;i++){var n=t[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,i,n){return i&&e(t.prototype,i),n&&e(t,n),t}}(),o=i(2),a=n(o),l=i(0),h=n(l);i(3);var u=new RegExp("/[\\n\\t]/","g"),d=100,f="rangeSlider",c=0,v=a.supportsRange(),p={polyfill:!0,rangeClass:"rangeSlider",disabledClass:"rangeSlider--disabled",fillClass:"rangeSlider__fill",bufferClass:"rangeSlider__buffer",handleClass:"rangeSlider__handle",startEvent:["mousedown","touchstart","pointerdown"],moveEvent:["mousemove","touchmove","pointermove"],endEvent:["mouseup","touchend","pointerup"],min:null,max:null,step:null,value:null,buffer:null,stick:null,borderRadius:10,vertical:!1},m=function(){function e(t,i){s(this,e);var n=void 0,r=void 0,o=void 0,l=void 0,u=void 0;if(this.element=t,this.options=h.simpleExtend(p,i),this.polyfill=this.options.polyfill,this.vertical=this.options.vertical,this.onInit=this.options.onInit,this.onSlide=this.options.onSlide,this.onSlideStart=this.options.onSlideStart,this.onSlideEnd=this.options.onSlideEnd,this.onSlideEventsCount=-1,this.isInteractsNow=!1,this.needTriggerEvents=!1,this.polyfill||!v){this.options.buffer=this.options.buffer||parseFloat(this.element.getAttribute("data-buffer")),this.identifier="js-"+f+"-"+c++,this.min=h.getFirsNumberLike(this.options.min,parseFloat(this.element.getAttribute("min")),n=0),this.max=h.getFirsNumberLike(this.options.max,parseFloat(this.element.getAttribute("max")),r=d),this.value=h.getFirsNumberLike(this.options.value,this.element.value,parseFloat(this.element.value||this.min+(this.max-this.min)/2)),this.step=h.getFirsNumberLike(this.options.step,parseFloat(this.element.getAttribute("step"))||(o=1)),this.percent=null,h.isArray(this.options.stick)&&this.options.stick.length>=1?this.stick=this.options.stick:(l=this.element.getAttribute("stick"))&&(u=l.split(" "),u.length>=1&&(this.stick=u.map(parseFloat))),this.stick&&1===this.stick.length&&this.stick.push(1.5*this.step),this._updatePercentFromValue(),this.toFixed=this._toFixed(this.step);var m=void 0;this.container=document.createElement("div"),a.addClass(this.container,this.options.fillClass),m=this.vertical?this.options.fillClass+"__vertical":this.options.fillClass+"__horizontal",a.addClass(this.container,m),this.handle=document.createElement("div"),a.addClass(this.handle,this.options.handleClass),m=this.vertical?this.options.handleClass+"__vertical":this.options.handleClass+"__horizontal",a.addClass(this.handle,m),this.range=document.createElement("div"),a.addClass(this.range,this.options.rangeClass),this.range.id=this.identifier,this.range.appendChild(this.handle),this.range.appendChild(this.container),m=this.vertical?this.options.rangeClass+"__vertical":this.options.rangeClass+"__horizontal",a.addClass(this.range,m),this.options.bufferClass&&(this.buffer=document.createElement("div"),a.addClass(this.buffer,this.options.bufferClass),this.range.appendChild(this.buffer),m=this.vertical?this.options.bufferClass+"__vertical":this.options.bufferClass+"__horizontal",a.addClass(this.buffer,m)),h.isNumberLike(this.options.value)&&(this._setValue(this.options.value,!0),this.element.value=this.options.value),h.isNumberLike(this.options.buffer)&&this.element.setAttribute("data-buffer",this.options.buffer),(h.isNumberLike(this.options.min)||n)&&this.element.setAttribute("min",""+this.min),(h.isNumberLike(this.options.max)||r)&&this.element.setAttribute("max",""+this.max),(h.isNumberLike(this.options.step)||o)&&this.element.setAttribute("step",""+this.step),a.insertAfter(this.element,this.range),a.setCss(this.element,{position:"absolute",width:"1px",height:"1px",overflow:"hidden",opacity:"0"}),this._handleDown=this._handleDown.bind(this),this._handleMove=this._handleMove.bind(this),this._handleEnd=this._handleEnd.bind(this),this._startEventListener=this._startEventListener.bind(this),this._changeEventListener=this._changeEventListener.bind(this),this._handleResize=this._handleResize.bind(this),this._init(),window.addEventListener("resize",this._handleResize,!1),a.addEventListeners(document,this.options.startEvent,this._startEventListener),this.element.addEventListener("change",this._changeEventListener,!1)}}return r(e,[{key:"update",value:function(e,t){return t&&(this.needTriggerEvents=!0),h.isObject(e)&&(h.isNumberLike(e.min)&&(this.element.setAttribute("min",""+e.min),this.min=e.min),h.isNumberLike(e.max)&&(this.element.setAttribute("max",""+e.max),this.max=e.max),h.isNumberLike(e.step)&&(this.element.setAttribute("step",""+e.step),this.step=e.step,this.toFixed=this._toFixed(e.step)),h.isNumberLike(e.buffer)&&this._setBufferPosition(e.buffer),h.isNumberLike(e.value)&&this._setValue(e.value)),this._update(),this.onSlideEventsCount=0,this.needTriggerEvents=!1,this}},{key:"destroy",value:function(){a.removeAllListenersFromEl(this,document),window.removeEventListener("resize",this._handleResize,!1),this.element.removeEventListener("change",this._changeEventListener,!1),this.element.style.cssText="",delete this.element[f],this.range&&this.range.parentNode.removeChild(this.range)}},{key:"_toFixed",value:function(e){return(e+"").replace(".","").length-1}},{key:"_init",value:function(){this.onInit&&"function"==typeof this.onInit&&this.onInit(),this._update()}},{key:"_updatePercentFromValue",value:function(){this.percent=(this.value-this.min)/(this.max-this.min)}},{key:"_startEventListener",value:function(e,t){var i=this,n=e.target,s=!1;(1===e.which||"touches"in e)&&(a.forEachAncestors(n,function(e){return s=e.id===i.identifier&&!a.hasClass(e,i.options.disabledClass)},!0),s&&this._handleDown(e,t))}},{key:"_changeEventListener",value:function(e,t){if(!t||t.origin!==this.identifier){var i=e.target.value,n=this._getPositionFromValue(i);this._setPosition(n)}}},{key:"_update",value:function(){var e=this.vertical?"offsetHeight":"offsetWidth";this.handleSize=a.getDimension(this.handle,e),this.rangeSize=a.getDimension(this.range,e),this.maxHandleX=this.rangeSize-this.handleSize,this.grabX=this.handleSize/2,this.position=this._getPositionFromValue(this.value),this.element.disabled?a.addClass(this.range,this.options.disabledClass):a.removeClass(this.range,this.options.disabledClass),this._setPosition(this.position),this.options.bufferClass&&this.options.buffer&&this._setBufferPosition(this.options.buffer),this._updatePercentFromValue(),a.triggerEvent(this.element,"change",{origin:this.identifier})}},{key:"_handleResize",value:function(){var e=this;return h.debounce(function(){h.delay(function(){e._update()},300)},50)()}},{key:"_handleDown",value:function(e){if(this.isInteractsNow=!0,e.preventDefault(),a.addEventListeners(document,this.options.moveEvent,this._handleMove),a.addEventListeners(document,this.options.endEvent,this._handleEnd),!((" "+e.target.className+" ").replace(u," ").indexOf(this.options.handleClass)>-1)){var t=this.range.getBoundingClientRect(),i=this._getRelativePosition(e),n=this.vertical?t.bottom:t.left,s=this._getPositionFromNode(this.handle)-n,r=i-this.grabX;this._setPosition(r),i>=s&&i<s+2*this.options.borderRadius&&(this.grabX=i-s),this._updatePercentFromValue()}}},{key:"_handleMove",value:function(e){var t=this._getRelativePosition(e);this.isInteractsNow=!0,e.preventDefault(),this._setPosition(t-this.grabX)}},{key:"_handleEnd",value:function(e){e.preventDefault(),a.removeEventListeners(document,this.options.moveEvent,this._handleMove),a.removeEventListeners(document,this.options.endEvent,this._handleEnd),a.triggerEvent(this.element,"change",{origin:this.identifier}),(this.isInteractsNow||this.needTriggerEvents)&&this.onSlideEnd&&"function"==typeof this.onSlideEnd&&this.onSlideEnd(this.value,this.percent,this.position),this.onSlideEventsCount=0,this.isInteractsNow=!1}},{key:"_setPosition",value:function(e){var t=void 0,i=void 0,n=void 0,s=void 0,r=this._getValueFromPosition(h.between(e,0,this.maxHandleX));this.stick&&(s=this.stick[0],i=this.stick[1]||.1,n=r%s,n<i?r-=n:Math.abs(s-n)<i&&(r=r-n+s)),t=this._getPositionFromValue(r),this.vertical?(this.container.style.height=t+this.grabX+"px",this.handle.style.transform="translateY(-"+t+"px)",this.handle.style["-ms-transform"]="translateY(-"+t+"px)"):(this.container.style.width=t+this.grabX+"px",this.handle.style.transform="translateX("+t+"px)",this.handle.style["-ms-transform"]="translateX("+t+"px)"),this._setValue(r),this.position=t,this.value=r,this._updatePercentFromValue(),(this.isInteractsNow||this.needTriggerEvents)&&(this.onSlideStart&&"function"==typeof this.onSlideStart&&0===this.onSlideEventsCount&&this.onSlideStart(this.value,this.percent,this.position),this.onSlide&&"function"==typeof this.onSlide&&this.onSlide(this.value,this.percent,this.position)),this.onSlideEventsCount++}},{key:"_setBufferPosition",value:function(e){var t=!0;if(isFinite(e))e=parseFloat(e);else{if(!h.isString(e))return void console.warn("New position must be XXpx or XX%");e.indexOf("px")>0&&(t=!1),e=parseFloat(e)}if(isNaN(e))return void console.warn("New position is NaN");if(!this.options.bufferClass)return void console.warn("You disabled buffer, it's className is empty");var i=t?e:e/this.rangeSize*100;i<0&&(i=0),i>100&&(i=100),this.options.buffer=i;var n=this.options.borderRadius/this.rangeSize*100,s=i-n;s<0&&(s=0),this.vertical?(this.buffer.style.height=s+"%",this.buffer.style.bottom=.5*n+"%"):(this.buffer.style.width=s+"%",this.buffer.style.left=.5*n+"%"),this.element.setAttribute("data-buffer",i)}},{key:"_getPositionFromNode",value:function(e){for(var t=this.vertical?this.maxHandleX:0;null!==e;)t+=this.vertical?e.offsetTop:e.offsetLeft,e=e.offsetParent;return t}},{key:"_getRelativePosition",value:function(e){var t=this.range.getBoundingClientRect(),i=this.vertical?t.bottom:t.left,n=0,s=this.vertical?"pageY":"pageX";return void 0!==e[s]?n=e.touches&&e.touches.length?e.touches[0][s]:e[s]:void 0!==e.originalEvent?void 0!==e.originalEvent[s]?n=e.originalEvent[s]:e.originalEvent.touches&&e.originalEvent.touches[0]&&void 0!==e.originalEvent.touches[0][s]&&(n=e.originalEvent.touches[0][s]):e.touches&&e.touches[0]&&void 0!==e.touches[0][s]?n=e.touches[0][s]:!e.currentPoint||void 0===e.currentPoint.x&&void 0===e.currentPoint.y||(n=this.vertical?e.currentPoint.y:e.currentPoint.x),this.vertical&&(n-=window.pageYOffset),this.vertical?i-n:n-i}},{key:"_getPositionFromValue",value:function(e){var t=(e-this.min)/(this.max-this.min),i=t*this.maxHandleX;return isNaN(i)?0:i}},{key:"_getValueFromPosition",value:function(e){var t=e/(this.maxHandleX||1),i=this.step*Math.round(t*(this.max-this.min)/this.step)+this.min;return Number(i.toFixed(this.toFixed))}},{key:"_setValue",value:function(e,t){(e!==this.value||t)&&(this.element.value=e,this.value=e,a.triggerEvent(this.element,"input",{origin:this.identifier}))}}],[{key:"create",value:function(t,i){var n=function(t){var n=t[f];n||(n=new e(t,i),t[f]=n)};t.length?Array.prototype.slice.call(t).forEach(function(e){n(e)}):n(t)}}]),e}();t.default=m,e.exports=t.default},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.supportsRange=t.removeAllListenersFromEl=t.removeEventListeners=t.addEventListeners=t.insertAfter=t.triggerEvent=t.forEachAncestors=t.removeClass=t.addClass=t.hasClass=t.setCss=t.getDimension=t.getHiddenParentNodes=t.isHidden=t.detectIE=void 0;var n=i(0),s=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t.default=e,t}(n),r=t.detectIE=function(){var e=window.navigator.userAgent,t=e.indexOf("MSIE ");if(t>0)return parseInt(e.substring(t+5,e.indexOf(".",t)),10);if(e.indexOf("Trident/")>0){var i=e.indexOf("rv:");return parseInt(e.substring(i+3,e.indexOf(".",i)),10)}var n=e.indexOf("Edge/");return n>0&&parseInt(e.substring(n+5,e.indexOf(".",n)),10)},o=r(),a=!(!window.PointerEvent||o)&&{passive:!1},l=t.isHidden=function(e){return 0===e.offsetWidth||0===e.offsetHeight||!1===e.open},h=t.getHiddenParentNodes=function(e){for(var t=[],i=e.parentNode;l(i);)t.push(i),i=i.parentNode;return t},u=(t.getDimension=function(e,t){var i=h(e),n=i.length,s=[],r=e[t],o=function(e){void 0!==e.open&&(e.open=!e.open)};if(n){for(var a=0;a<n;a++)s[a]=i[a].style.display,i[a].style.display="block",i[a].style.height="0",i[a].style.overflow="hidden",i[a].style.visibility="hidden",o(i[a]);r=e[t];for(var l=0;l<n;l++)o(i[l]),i[l].style.display=s[l],i[l].style.height="",i[l].style.overflow="",i[l].style.visibility=""}return r},t.setCss=function(e,t){for(var i in t)e.style[i]=t[i];return e.style},t.hasClass=function(e,t){return new RegExp(" "+t+" ").test(" "+e.className+" ")});t.addClass=function(e,t){u(e,t)||(e.className+=" "+t)},t.removeClass=function(e,t){var i=" "+e.className.replace(/[\t\r\n]/g," ")+" ";if(u(e,t)){for(;i.indexOf(" "+t+" ")>=0;)i=i.replace(" "+t+" "," ");e.className=i.replace(/^\s+|\s+$/g,"")}},t.forEachAncestors=function(e,t,i){for(i&&t(e);e.parentNode&&!t(e);)e=e.parentNode;return e},t.triggerEvent=function(e,t,i){if(!s.isString(t))throw new TypeError("event name must be String");if(!(e instanceof HTMLElement))throw new TypeError("element must be HTMLElement");t=t.trim();var n=document.createEvent("CustomEvent");n.initCustomEvent(t,!1,!1,i),e.dispatchEvent(n)},t.insertAfter=function(e,t){return e.parentNode.insertBefore(t,e.nextSibling)},t.addEventListeners=function(e,t,i){t.forEach(function(t){e.eventListenerList||(e.eventListenerList={}),e.eventListenerList[t]||(e.eventListenerList[t]=[]),e.addEventListener(t,i,a),e.eventListenerList[t].indexOf(i)<0&&e.eventListenerList[t].push(i)})},t.removeEventListeners=function(e,t,i){t.forEach(function(t){var n=void 0;e.removeEventListener(t,i,!1),e.eventListenerList&&e.eventListenerList[t]&&(n=e.eventListenerList[t].indexOf(i))>-1&&e.eventListenerList[t].splice(n,1)})},t.removeAllListenersFromEl=function(e,t){function i(t){t===e._startEventListener&&this.el.removeEventListener(this.eventName,t,!1)}if(t.eventListenerList){for(var n in t.eventListenerList)t.eventListenerList[n].forEach(i,{eventName:n,el:t});t.eventListenerList={}}},t.supportsRange=function(){var e=document.createElement("input");return e.setAttribute("type","range"),"text"!==e.type}},function(e,t){}])}); | |
| //# sourceMappingURL=range-slider.min.js.map |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment