L-System
How do I make an l-system?
Recently fascinated by L-Systems, named after Aristid Lindenmayer. Read more about it: * L-System wikipedia . What is a l-system? How do you make a l-system? This script and codes were developed by Pimskie on 16 September 2022, Friday.
L-System - Script Codes HTML Codes
<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>L-System</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css"> <link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="controls"> <select class="js-curve"> <option value="hilbert">Hilbert</option> <option value="koch">koch</option> <option value="kochSnowflake">koch snowflake</option> <option value="sierpinski">sierpinski</option> <option value="sierpinskiArrowHead">sierpinskiArrowHead</option> <option value="levy" >Lévy C curve</option> <option value="peanoGosper">Peano-Gosper Curve</option> <option value="peano">Peano Curve</option> <option value="dragon" selected>Dragon curve</option> <option value="tree">Tree</option> <option value="tree2">Tree 2</option> </select>
</div>
<canvas class="canvas js-canvas" width="500" height="500"></canvas> <script src="js/index.js"></script>
</body>
</html>
L-System - Script Codes CSS Codes
html,
body { margin: 0; padding: 0; overflow: hidden;
}
.controls,
.canvas { position: absolute;
}
.controls { z-index: 10; top: 0; right: 0;
}
.canvas { z-index: 1; display: block;
}
L-System - Script Codes JS Codes
'use strict';
var qs = function qs(sel) { return document.querySelector(sel);
};
var toRadian = Math.PI / 180;
var canvas = qs('canvas');
var ctx = canvas.getContext('2d');
var width = window.innerWidth;
var height = window.innerHeight;
canvas.width = width;
canvas.height = height;
var maxDepth = 6;
var defaultScale = 10;
var curveScale = defaultScale;
var dimensions = { minX: null, maxX: null, minY: null, maxY: null
};
var currentDepth = 0;
var currentAngle = 0;
var hilbert = { axiom: 'A', result: 'A', variables: ['A', 'B'], rules: { 'A': '-BF+AFA+FB-', 'B': '+AF-BFB-FA+' }, angle: 90 * toRadian
};
var koch = { axiom: 'F', result: 'F', rules: { 'F': 'F+F-F-F+F' }, angle: 90 * toRadian
};
var kochSnowflake = { axiom: 'F++F++F', result: 'F', rules: { 'F': 'F-F++F-F' }, angle: 60 * toRadian
};
var sierpinski = { axiom: 'F-G-G', result: 'F-G-G', rules: { 'F': 'F-G+F+G-F', 'G': 'GG' }, angle: 120 * toRadian
};
var sierpinskiArrowHead = { axiom: 'A', result: 'A', rules: { 'A': '+B-A-B+', 'B': '-A+B+A-' }, angle: 60 * toRadian, maxDepth: 8
};
var levy = { axiom: 'F', result: 'F', rules: { 'F': '+F--F+' }, angle: -45 * toRadian, maxDepth: 15
};
var tree = { axiom: 'X', result: 'X', rules: { 'X': 'F-[[X]+X]+F[+FX]-X', 'F': 'FF' }, angle: -25 * toRadian, startAngle: -90 * toRadian, stack: []
};
var tree2 = { axiom: 'X', result: 'X', rules: { 'X': 'F[+X][-X]FX', 'F': 'FF' }, angle: -25.7 * toRadian, startAngle: -90 * toRadian, stack: []
};
var peanoGosper = { axiom: 'A', result: 'A', rules: { 'A': 'A-B--B+A++AA+B-', 'B': '+A-BB--B-A++A+B' }, startAngle: 0, angle: 60 * toRadian, stack: [], maxDepth: 5
};
var peano = { axiom: 'F', result: 'F', rules: { 'F': 'F+F-F-F-F+F+F+F-F' }, maxDepth: 4, angle: 90 * toRadian, stack: []
};
var dragon = { axiom: 'FX', result: 'FX', variables: ['X', 'Y'], rules: { 'X': 'X+YF+', 'Y': '-DX-Y' }, angle: 90 * toRadian, stack: [], maxDepth: 15
};
var presets = { hilbert: hilbert, koch: koch, kochSnowflake: kochSnowflake, sierpinski: sierpinski, sierpinskiArrowHead: sierpinskiArrowHead, levy: levy, tree: tree, tree2: tree2, peanoGosper: peanoGosper, peano: peano, dragon: dragon
};
var x = 0;
var y = 0;
var clear = function clear() { ctx.clearRect(0, 0, width, height);
};
var adjustAngle = function adjustAngle(curve, plusMinus) { if (plusMinus === '+') { currentAngle -= curve.angle; } else { currentAngle += curve.angle; }
};
var stackPush = function stackPush(curve) { curve.stack.push([x, y, currentAngle]);
};
var stackPop = function stackPop(curve) { var _curve$stack$pop = curve.stack.pop(); x = _curve$stack$pop[0]; y = _curve$stack$pop[1]; currentAngle = _curve$stack$pop[2];
};
var drawLine = function drawLine(curve, instruction) { var runForDimensions = arguments.length <= 2 || arguments[2] === undefined ? true : arguments[2]; var nextX = x + Math.cos(currentAngle) * curveScale; var nextY = y + Math.sin(currentAngle) * curveScale; if (!runForDimensions) { ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(nextX, nextY); ctx.stroke(); ctx.closePath(); } x = nextX; y = nextY; if (runForDimensions) { if (!dimensions.minX || x < dimensions.minX) { dimensions.minX = x; } if (!dimensions.maxX || x > dimensions.maxX) { dimensions.maxX = x; } if (!dimensions.minY || y < dimensions.minY) { dimensions.minY = y; } if (!dimensions.maxY || y > dimensions.maxY) { dimensions.maxY = y; } }
};
/** * Draws a curve, sort of.. * * Used in two ways: * first to draw the pattern with a default line length, and get the dimensions * This run isn't painted on the canvas. - runForDimensions = true * * Second, draw and paint the pattern. But with the dimensions of the first run, * scaling and positioning is applied so it fits the screen. - runForDimensions = false */
var drawCurve = function drawCurve(curve) { var runForDimensions = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; clear(); x = 0; y = 0; currentAngle = curve.startAngle || 0; currentDepth = 0; curve.stack = []; // remove the variables from the result string, they aren't needed anymore var variablesPattern = (curve.variables || []).join('|'); var regex = new RegExp(variablesPattern, 'g'); var lSystemString = curve.result.replace(regex, ''); // by splitting the filtered string, we have a list of instructions (turn left, turn right, draw, etc) var curveInstructions = lSystemString.split(''); // TODO: make this better, clearer if (!runForDimensions) { var w = (Math.abs(dimensions.minX) + dimensions.maxX) / (defaultScale / curveScale); var h = (Math.abs(dimensions.minY) + dimensions.maxY) / (defaultScale / curveScale); var offsetX = Math.abs(dimensions.minX) / (defaultScale / curveScale) + width * 0.5 - w * 0.5; var offsetY = -dimensions.minY / (defaultScale / curveScale) + height * 0.5 - h * 0.5; ctx.save(); ctx.translate(offsetX, offsetY); } curveInstructions.forEach(function (instruction) { var method = map[instruction] || drawLine; method(curve, instruction, runForDimensions); }); if (!runForDimensions) { ctx.restore(); }
};
var reset = function reset(curve) { x = 0; y = 0; dimensions = { minX: null, maxX: null, minY: null, maxY: null }; currentAngle = curve.startAngle || 0; currentDepth = 0; curveScale = defaultScale; curve.stack = []; curve.result = curve.axiom;
};
var generate = function generate(curve) { reset(curve); var maxLoops = curve.maxDepth || maxDepth; /** * this is the core, the most important part * within every loop, the alphabeth chararcter (A, B, X, F, etc) gets replaced by their rule * * Since the rule contains one or more alphabeth characters, the product gets longer and longer */ while (currentDepth < maxLoops) { var pattern = Object.keys(curve.rules).join('|'); var regex = new RegExp(pattern, 'g'); curve.result = curve.result.replace(regex, function (match) { return curve.rules[match]; }); currentDepth++; } // first a 'dry run': don't paint anything, but get the dimensions of the pattern drawCurve(curve, true); // with the dimensions, a scaling can be calculated so it fits the screen var totalWidth = Math.abs(dimensions.minX) + dimensions.maxX; var totalHeight = Math.abs(dimensions.minY) + dimensions.maxY; var scaleWidth = window.innerWidth / totalWidth; var scaleHeight = window.innerHeight / totalHeight; curveScale = defaultScale * Math.min(scaleWidth, scaleHeight); // with that information, the pattern can be drawn on the canvas drawCurve(curve, false);
};
var map = { '+': adjustAngle, '-': adjustAngle, '[': stackPush, ']': stackPop
};
var presetSelect = qs('.js-curve');
presetSelect.addEventListener('change', function (e) { generate(presets[e.target.value]);
});
generate(presets[presetSelect.value]);
Developer | Pimskie |
Username | pimskie |
Uploaded | September 16, 2022 |
Rating | 3.5 |
Size | 6,807 Kb |
Views | 32,384 |
Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!
Name | Size |
Wave | 3,651 Kb |
Predictabe Flower | 5,881 Kb |
Aizawa Attractor | 3,609 Kb |
Apollonian gasket | 9,268 Kb |
Flowing transforming circle | 3,841 Kb |
A Pen by pimskie | 2,486 Kb |
Planet attractors | 4,548 Kb |
Particles Clifford attractor | 3,448 Kb |
Rotatable grid | 4,455 Kb |
Circles pattern | 3,342 Kb |
Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!
Name | Username | Size |
Scifi-style Interative Form | Aaronchuo | 4,566 Kb |
Working around OS X Dynamic Scrollbars | Jrjenk | 2,279 Kb |
Yuliya v krylova | Rafszul | 37,351 Kb |
Drag n Drop | Martin42 | 2,594 Kb |
Highbrow Basic HTML Lesson 8 | Kimlarocca | 2,094 Kb |
Rows with image hover effect | Amit-webdesigner | 12,875 Kb |
IPhone5S SVG Space Grey | Onlinechris | 75,035 Kb |
Christ the Redeemer | Prashantsani | 2,208 Kb |
A Pen by Eka Risyana | Risyana | 3,705 Kb |
Flat UI - Checkbox FIX | ARS | 2,663 Kb |
Surf anonymously, prevent hackers from acquiring your IP address, send anonymous email, and encrypt your Internet connection. High speed, ultra secure, and easy to use. Instant setup. Hide Your IP Now!