mirror of
https://github.com/Sheldan/canvas.git
synced 2026-04-13 11:31:37 +00:00
collatzConjecture: initial adding
clusterFilter: fixing package.json
This commit is contained in:
60
collatzConjecture/src/index.html
Normal file
60
collatzConjecture/src/index.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<!doctype html>
|
||||
<html class="no-js" lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>collatzConjecture</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
html, body, div, canvas {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body { width:100%; height:100%; }
|
||||
canvas { display:block; }
|
||||
/*.controls {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 10px
|
||||
}*/
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<label for="heightChange">Size of tree</label>
|
||||
<input type="range" value="25" min="1" max="50" id="heightChange" oninput="setNewHeightChange(this.value)">
|
||||
<label for="spread">Spread</label>
|
||||
<input type="range" value="5" min="1" id="spread" oninput="setNewSpread(this.value)" max="30">
|
||||
|
||||
|
||||
<label for="firstNumber">First number</label>
|
||||
<input type="range" value="2" min="1" max="50" id="firstNumber" oninput="setNewFirstNumber(this.value)">
|
||||
<label for="secondNumber">Second number</label>
|
||||
<input type="range" value="3" min="1" id="secondNumber" oninput="setNewSecondNumber(this.value)" max="50">
|
||||
|
||||
<label for="size">Canvas Size:</label>
|
||||
<input type="number" id="size" max="10000" onblur="updateCanvasConfig(this.value)">
|
||||
<input type="button" value="reinitialize colors" onclick="generateColors(); updateCanvas()">
|
||||
<br>
|
||||
Explanation of first and second number:
|
||||
The typical conjecture is in the form of: 3n + 1 with the property of dividing by two if odd etc.... (Explanation <a href="https://en.wikipedia.org/wiki/Collatz_conjecture">here</a>). <br> The 'firstNumber' is the 2 in the formula and the 'secondNumber' the 3.
|
||||
Beware of ... interesting outcomes as this can cause the created tree to become very large... often too much for the browser.
|
||||
<br>
|
||||
<span>
|
||||
Height:
|
||||
<span id="heightValue"></span>
|
||||
Spread:
|
||||
<span id="spreadValue"></span>
|
||||
Firstnumber:
|
||||
<span id="firstValue"></span>
|
||||
Secondnumber:
|
||||
<span id="secondValue"></span>
|
||||
</span>
|
||||
<br>
|
||||
<a id="download" onclick="downloadCanvasCommon('collatzConjecture', canvas)">Download</a>
|
||||
<br>
|
||||
<canvas id="canvas"></canvas>
|
||||
|
||||
<script type="module" src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
242
collatzConjecture/src/js/main.js
Normal file
242
collatzConjecture/src/js/main.js
Normal file
@@ -0,0 +1,242 @@
|
||||
import {
|
||||
docReady, d2h, toRad, downloadCanvasWithoutButton
|
||||
} from "canvas-common";
|
||||
|
||||
|
||||
|
||||
var ctx = {};
|
||||
var canvas = {};
|
||||
|
||||
var used = {};
|
||||
var colors = [];
|
||||
var collatzTree;
|
||||
|
||||
var heightChange;
|
||||
var sizeInput;
|
||||
var spreadInput;
|
||||
var heightValue;
|
||||
var spreadValue;
|
||||
var firstValue;
|
||||
var secondValue;
|
||||
|
||||
var startCol = {r: 0, g: 0, b: 0};
|
||||
var finalCol = {r: 0, g: 0, b: 0};
|
||||
var colorPoints = [];
|
||||
|
||||
function setToPinkishColors() {
|
||||
colorPoints.push({r: 38, g: 17, b: 43});
|
||||
colorPoints.push({r: 86, g: 37, b: 81});
|
||||
colorPoints.push({r: 132, g: 60, b: 107});
|
||||
colorPoints.push({r: 171, g: 88, b: 126});
|
||||
colorPoints.push({r: 202, g: 122, b: 142});
|
||||
colorPoints.push({r: 224, g: 159, b: 161});
|
||||
colorPoints.push({r: 238, g: 198, b: 189});
|
||||
colorPoints.push({r: 249, g: 237, b: 229});
|
||||
finalCol = colorPoints[colorPoints.length - 1];
|
||||
}
|
||||
|
||||
|
||||
var config = {
|
||||
size: {
|
||||
size: 1500
|
||||
},
|
||||
conjectureConfig: {
|
||||
firstNumber: 2,
|
||||
secondNumber: 3,
|
||||
maxDepth: 30,
|
||||
heightChange: 25,
|
||||
dirChange: 10
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function buildStructure(input, depth) {
|
||||
if (depth > config.conjectureConfig.maxDepth) return undefined;
|
||||
if (input in used) {
|
||||
return undefined
|
||||
}
|
||||
depth++;
|
||||
used[input] = 1;
|
||||
var element = {};
|
||||
element.num = input;
|
||||
var child1 = buildStructure(input * config.conjectureConfig.firstNumber, depth);
|
||||
var child2 = undefined;
|
||||
var inputSmaller = input - 1;
|
||||
var probableNumber = (inputSmaller) / config.conjectureConfig.secondNumber;
|
||||
if ((inputSmaller) % config.conjectureConfig.secondNumber == 0 && (probableNumber % config.conjectureConfig.firstNumber != 0)) {
|
||||
child2 = buildStructure(probableNumber, depth);
|
||||
}
|
||||
element.child1 = child1;
|
||||
element.child2 = child2;
|
||||
return element;
|
||||
}
|
||||
|
||||
function setNewHeightChange(newValue) {
|
||||
config.conjectureConfig.heightChange = parseInt(newValue);
|
||||
heightValue.innerText = config.conjectureConfig.heightChange;
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
function setNewSpread(newValue) {
|
||||
config.conjectureConfig.dirChange = parseInt(newValue);
|
||||
spreadValue.innerText = config.conjectureConfig.dirChange;
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
// TODO fix with different amount of colors
|
||||
function drawElement(input, dir, parentPos, depth) {
|
||||
if (depth >= config.conjectureConfig.maxDepth || input in used) return;
|
||||
//console.log('__________________')
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(parentPos.x, parentPos.y);
|
||||
var numberOfStepsEachColor = Math.round(config.conjectureConfig.maxDepth / colorPoints.length);
|
||||
// often... this returns a higher color, but the ratio is still in above 0.5, so the color changes drastically
|
||||
var whereToMoveColorWise = (~~((depth) / config.conjectureConfig.maxDepth * 0.995 * colorPoints.length) + 1);
|
||||
var ratio = (depth % (numberOfStepsEachColor)) / ((numberOfStepsEachColor));
|
||||
// sometimes a color to high is chosen with a high ratio, this causes the color change to be wrong (and very drastic)
|
||||
// we need to go a step back
|
||||
if (ratio >= 1) {
|
||||
whereToMoveColorWise--;
|
||||
}
|
||||
else if (ratio > 0.5) {
|
||||
whereToMoveColorWise = (~~((depth - 1) / config.conjectureConfig.maxDepth * 0.995 * colorPoints.length) + 1);
|
||||
}
|
||||
|
||||
var targetColor = colorPoints[whereToMoveColorWise];
|
||||
if (whereToMoveColorWise == colorPoints.length) {
|
||||
targetColor = finalCol;
|
||||
}
|
||||
var whereWeComeColorWise = whereToMoveColorWise - 1;
|
||||
//console.log(whereWeComeColorWise + '_' + whereToMoveColorWise)
|
||||
//console.log(depth + '_' + numberOfStepsEachColor)
|
||||
//console.log(ratio + '_' + depth / config.conjectureConfig.maxDepth)
|
||||
|
||||
var baseColor = colorPoints[whereWeComeColorWise];
|
||||
var newColor = {
|
||||
r: targetColor.r * ratio + baseColor.r * (1 - ratio),
|
||||
g: targetColor.g * ratio + baseColor.g * (1 - ratio),
|
||||
b: targetColor.b * ratio + baseColor.b * (1 - ratio)
|
||||
};
|
||||
ctx.strokeStyle = '#' + d2h(~~newColor.r) + d2h(~~newColor.g) + d2h(~~newColor.b);
|
||||
var newXOffset = config.conjectureConfig.heightChange * Math.cos(toRad(dir));
|
||||
//console.log(ctx.strokeStyle)
|
||||
//console.log(newColor)
|
||||
//console.log(baseColor)
|
||||
//console.log(targetColor)
|
||||
var newYOffset = config.conjectureConfig.heightChange * Math.sin(toRad(dir));
|
||||
//ctx.fillText((ctx.strokeStyle) + ' ', parentPos.x, parentPos.y);
|
||||
ctx.lineTo(parentPos.x + newXOffset, parentPos.y + newYOffset);
|
||||
ctx.stroke();
|
||||
// experiment to use two parallel lines represented in the video, doesn't work that well, because the line can cross the other line and then... stuff happens
|
||||
// also lines overlay each other
|
||||
//ctx.strokeStyle = colors[depth + 1];
|
||||
//ctx.moveTo(parentPos.x - Math.cos(toRad(90 - dir)) * config.width / 2, parentPos.y - Math.sin(toRad(90 - dir)) * config.width / 2);
|
||||
//ctx.lineTo(parentPos.x + config.heightChange * Math.cos(toRad(dir)) - Math.cos(toRad(90 - dir)) * config.width / 2,
|
||||
// parentPos.y + config.heightChange * Math.sin(toRad(dir)) - Math.sin(toRad(90 - dir)) * config.width / 2);
|
||||
//
|
||||
//ctx.moveTo(parentPos.x + Math.cos(toRad(90 - dir)) * config.width / 2, parentPos.y + Math.sin(toRad(90 - dir)) * config.width / 2);
|
||||
//ctx.lineTo(parentPos.x + config.heightChange * Math.cos(toRad(dir)) + Math.cos(toRad(90 - dir)) * config.width / 2,
|
||||
// parentPos.y + config.heightChange * Math.sin(toRad(dir)) + Math.sin(toRad(90 - dir)) * config.width / 2);
|
||||
//ctx.stroke();
|
||||
var newParentPos = {
|
||||
x: parentPos.x + newXOffset,
|
||||
y: parentPos.y + newYOffset
|
||||
};
|
||||
depth++;
|
||||
used[input] = 1;
|
||||
drawElement(input * config.conjectureConfig.firstNumber, dir + config.conjectureConfig.dirChange, newParentPos, depth);
|
||||
var inputSmaller = input - 1;
|
||||
var probableNumber = (inputSmaller) / config.conjectureConfig.secondNumber;
|
||||
if ((inputSmaller) % config.conjectureConfig.secondNumber == 0 && (probableNumber % config.conjectureConfig.firstNumber != 0)) {
|
||||
drawElement(probableNumber, dir - config.conjectureConfig.dirChange, newParentPos, depth);
|
||||
}
|
||||
else {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
function generateColors() {
|
||||
colors = [];
|
||||
colorPoints = [];
|
||||
colorPoints.push(startCol);
|
||||
var maxInc = (255 / config.conjectureConfig.maxDepth);
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var red = ~~(Math.random() * 255);
|
||||
var green = ~~(Math.random() * 255);
|
||||
var blue = ~~(Math.random() * 255);
|
||||
//colors.push('#' + (red).toString(16) + (green).toString(16) + (blue).toString(16));
|
||||
colorPoints.push({r: red, g: green, b: blue});
|
||||
}
|
||||
}
|
||||
|
||||
function updateCanvasConfig(newValue) {
|
||||
config.size.size = parseInt(newValue);
|
||||
initCanvas();
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
function updateCanvas() {
|
||||
used = {};
|
||||
ctx.clearRect(0, 0, config.size.size, config.size.size);
|
||||
drawElement(1, -180, config.size, 0);
|
||||
}
|
||||
|
||||
function setNewFirstNumber(newVal) {
|
||||
config.conjectureConfig.firstNumber = parseInt(newVal);
|
||||
firstValue.innerText = config.conjectureConfig.firstNumber;
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
function setNewSecondNumber(newVal) {
|
||||
config.conjectureConfig.secondNumber = parseInt(newVal);
|
||||
secondValue.innerText = config.conjectureConfig.secondNumber;
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
function initCanvas() {
|
||||
ctx = canvas.getContext("2d");
|
||||
canvas.height = config.size.size;
|
||||
canvas.width = config.size.size;
|
||||
config.size.x = config.size.size / 2;
|
||||
config.size.y = config.size.size / 2;
|
||||
}
|
||||
docReady(function () {
|
||||
canvas = document.getElementById('canvas');
|
||||
initCanvas();
|
||||
|
||||
ctx.font = "8px Verdana";
|
||||
ctx.lineWidth = 1;
|
||||
sizeInput = document.getElementById('size');
|
||||
heightChange = document.getElementById('heightChange');
|
||||
spreadInput = document.getElementById('spread');
|
||||
|
||||
heightValue = document.getElementById('heightValue');
|
||||
heightValue.innerText = config.conjectureConfig.heightChange;
|
||||
spreadValue = document.getElementById('spreadValue');
|
||||
spreadValue.innerText = config.conjectureConfig.dirChange;
|
||||
firstValue = document.getElementById('firstValue');
|
||||
firstValue.innerText = config.conjectureConfig.firstNumber;
|
||||
secondValue = document.getElementById('secondValue');
|
||||
secondValue.innerText = config.conjectureConfig.secondNumber;
|
||||
|
||||
sizeInput.value = config.size.size;
|
||||
spreadInput.value =config.conjectureConfig.dirChange;
|
||||
heightChange.value = config.conjectureConfig.heightChange;
|
||||
setToPinkishColors();
|
||||
//generateColors();
|
||||
drawElement(1, -180, config.size, 0);
|
||||
//initStructure();
|
||||
});
|
||||
|
||||
function downloadCanvasCollatz() {
|
||||
downloadCanvasWithoutButton('collatzConjecture', canvas);
|
||||
}
|
||||
|
||||
window.setNewHeightChange = setNewHeightChange;
|
||||
window.setNewSpread = setNewSpread;
|
||||
window.setNewFirstNumber = setNewFirstNumber;
|
||||
window.setNewSecondNumber = setNewSecondNumber;
|
||||
window.updateCanvasConfig = updateCanvasConfig;
|
||||
window.generateColors = generateColors;
|
||||
window.updateCanvas = updateCanvas;
|
||||
window.downloadCanvasCommon = downloadCanvasCollatz;
|
||||
24
collatzConjecture/src/js/plugins.js
Normal file
24
collatzConjecture/src/js/plugins.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// Avoid `console` errors in browsers that lack a console.
|
||||
(function() {
|
||||
var method;
|
||||
var noop = function () {};
|
||||
var methods = [
|
||||
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
|
||||
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
|
||||
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
|
||||
'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
|
||||
];
|
||||
var length = methods.length;
|
||||
var console = (window.console = window.console || {});
|
||||
|
||||
while (length--) {
|
||||
method = methods[length];
|
||||
|
||||
// Only stub undefined methods.
|
||||
if (!console[method]) {
|
||||
console[method] = noop;
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
// Place any jQuery/helper plugins in here.
|
||||
Reference in New Issue
Block a user