svg模仿指纹纹理效果代码

代码语言:html

所属分类:背景

代码描述:svg模仿指纹纹理效果代码

代码标签: 纹理 效果

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="UTF-8">




    <style>
        document, body {
            background: #111122;
            margin: 0;
            min-height: 100vh;
        }

        body {
            align-items: center;
            display: flex;
            justify-content: center;
        }

        #container {
            align-items: center;
            display: flex;
            flex-direction: column;
        }

        #container > :first-child {
            cursor: pointer;
        }

        button {
            max-width: 200px;
            margin-top: 10px;
        }

        .tracer {
            color: #fff;
        }
    </style>




</head>

<body>
    <div id="container"></div>


    <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/svg.min.js"></script>
    <script type="module">

        import {
            Vec2
        } from 'https://cdn.skypack.dev/wtc-math';
        import fitCurve from 'https://cdn.skypack.dev/fit-curves';
        console.clear();

        const config = {
            seed: 1337,
            drawingType: 1,
            dimensions: new Vec2(700, 700),
            nscale: .00125,
            sscale: 20,
            stepSize: 25,
            num: 1,
            r: 5,
            k: 8,
            testGridSize: 1,
            offset: new Vec2(10, -200),
            sneks: 200
        };
        const vars = {
            noise: null,
            grid: null,
            drawing: null
        }
        const setup = () => {
            const container = document.querySelector('#container');

            config.offset.x = floatRandomBetween(-1000, 1000);
            config.offset.y = floatRandomBetween(-1000, 1000);
            config.nscale = floatRandomBetween(.000005, .002);

            container.innerHTML = '';

            vars.drawing = new Drawing(config.drawingType).addTo('#container').size(config.dimensions);

            const t = document.createElement('div')
            t.className = 'tracer';
            container.appendChild(t)

            vars.bluenoise = new BlueNoise({
                size: config.dimensions.addNew(new Vec2(config.r*-1, config.r*-1)),
                offset: new Vec2(config.r*1, config.r*1),
                r: config.r,
                k: config.k
            });
            vars.noise = new SimplexNoise(config.seed);
            vars.grid = new Grid({
                cellSize: new Vec2(config.testGridSize, config.testGridSize), fill: -1
            });

            /// Create the download button
            // const dl = document.createElement('button');
            // dl.innerText = 'download';
            // dl.addEventListener('click', () => {
            //   vars.drawing.download();
            // });
            // container.appendChild(dl);

            document.body.querySelector('#container>:first-child').addEventListener('click', () => {
                setup();
            });

            draw(); drawStep();
        }

        let sneki = 0;
        const drawStep = () => {
            const sneks = [];
            if (vars.bluenoise.news.length > 0) {
                requestAnimationFrame(drawStep)
                for (let i = 0; i < config.sneks; i++) {
                    const [p] = vars.bluenoise.news.splice(Math.floor(Math.random() * vars.bluenoise.news.length), 1.);
                    if (!p) continue;
                    if (p.subtractNew(config.dimensions.scaleNew(.5)).length > 200) continue;
                    const pos = p;

                    const dir = new Vec2(1, 0);
                    const f = field(pos, 1., sneki+1);
                    dir.angle = f.noise;

                    // vars.drawing.stroke = '#ff0000AA';
                    // vars.drawing.circle(pos, 1);

                    const distancebreak = 3;
                    let cont = false;
                    for (let x = -distancebreak*.5; x <= distancebreak*.5; x++) {
                        for (let y = -distancebreak*.5; y <= distancebreak*.5; y++) {
                            const offset = new Vec2(x, y);
                            const t = vars.grid.getChildAtPosition(pos.addNew(offset));
                            if (t !== -1) cont = true;
                        }
                    }
                    if (cont) continue;

                    // vars.drawing.circle(pos, .5);

                    const s = new Snek(pos, {
                        direction: dir,
                        maxLength: 2000,
                        id: sneki++,
                        distanceProjection: 5,
                        distanceBreak: distancebreak,
                        projectionBreakMultiplier: 0
                    });
                    sneks.push(s);
                    //        projectionBreakMultiplier: 2
                    //
                }
            }

            // for(let j = 0; j < config.lineLength; j++) {
            for (let i = 0; i < sneks.length; i++) {
                sneks[i].walkOut();
            }
            // }

            // document.querySelector('.tracer').innerHTML = vars.bluenoise.news.length;
            for (let i = 0; i < sneks.length; i++) {
                vars.drawing.path(sneks[i].bezier);
            }
        }
        let interval;
        const draw = () => {

            vars.drawing.stroke = '#AAA';
            vars.drawing.c.fillStyle = "#111122";
            vars.drawing.c.fillRect(0, 0, config.dimensions.x, config.dimensions.y);

            vars.drawing.rect(new Vec2(0, 0), config.dimensions);
            vars.drawing.c.lineWidth = 1.5;

            while (vars.bluenoise.active.length > 0) {
                vars.bluenoise.step();
            }
        }

        setTimeout(() => {
            setup();
        }, 500);

        const ngon = (pos, r, nsides) => {
            const a = Math.atan2(pos.y, pos.x) + Math.PI*.5;
            const split = (Math.PI*2) / nsides;
            return pos.length * Math.cos(split * Math.floor(.5 + a / split) - a) - r;
        }

        const field = (pos, id = 1, instanceID = 0)=> {
            const normpos = pos.subtractNew(config.dimensions.scaleNew(.5));
            const mask1 = ngon(normpos, 200, 40) < Math.random()*10;
            const mask2 = ngon(normpos.addNew(new Vec2(0, 50)), 250, 3) < 0.;
            let mask;
            if (!id) {
                if (mask2) {
                    id = 2.;
                } else if (mask1) {
                    id = 1.;
                }
            }

            let n;

            if (id == 1.) {
                n = vars.noise.noise2D(pos.addNew(config.offset).scale(config.nscale).array)*Math.PI;
                // const a = Math.atan2(normpos.y, normpos.x);
                // n = a - .5;
            } else if (id == 2.) {
                // const a = Math.atan2(normpos.y, normpos.x) + Math.PI * .5;
                // n = a + .8;

                const a = Math.atan2(normpos.y, normpos.x);
                n = a + .5;

                // n = noise.noise2D(pos.addNew(config.offset).scale(config.nscale).array)*Math.PI;
            }

            // let apos = pos.subtractNew(dimensions.scaleNew(.5));
            // let a = Math.atan2(apos.y, apos.x) + Math.PI * .5;

            // const n = noise.noise2D(pos.addNew(config.offset).scale(config.nscale).array)*Math.PI;

            // const n = a + .8;

            // const mask = pos.subtractNew(dimensions.scaleNew(.5)).length < 350;
            // const mask = ngon(normpos, 150, 3) < 0.;
            return {
                noise: n,
                mask: instanceID % 3 == 0 ? true: mask1,
                id: id
            };
        }

        class Snek {
            static #defaults = {
                grid: vars.grid,
                head: true,
                tail: true,
                direction: new Vec2(1, 0),
                maxLength: 1000,
                stepSize: 1,
                fieldID: 1,
                distanceBreak: 5,
                distanceProjection: 5,
                minLength: 10,
                id: 0,
                bailout: 10000,
                projectionBreakMultiplier: .5
            };
            #alive = [true,
                true]; /* Two alive directions per snek */
            #directions = [0,
                0]; /* The direction of the head and tail */
            #positions = [0,
                0]; /* The position of the head and tail */
            #maxLength = 1000; /* The maximum length of the whole snake */
            #stepSize = 1;
            #fieldID = 1;
            #distanceBreak = 5;
            #distanceProjection = 5;
            #minLength = 5;
            #points = [];
            #id = 0;
            #bailout = 10000;
            #projectionBreakMultiplier = .5;

            constructor(pos, settings) {
                settings = Object.assign({}, Snek.#defaults, settings);
                this.#alive[0] = settings.head === true;
                this.#alive[1] = settings.tail === true;
                this.directionHead = settings.direction.clone();
                this.directionTail = settings.direction.rotateNew(Math.PI);
                this.#positions[0] = pos.clone();
                this.#positions[1] = pos.clone();
                this.#fieldID = settings.fieldID;
                this.#distanceBreak = settings.distanceBreak;
                this.#distanceProjection = settings.distanceProjection;
                this.#maxLength = settings.maxLength;
                this.#minLength = settings.minLength;
                this.#id = settings.id;
                this.#bailout = settings.bailout;
                this.#projectionBreakMultiplier = settings.projectionBreakMultiplier;
            }
            walkOut() {
                // console.log(this.length, this.#maxLength)
                let i = 0;
                while (this.length < this.#maxLength) {
                    if (i++ > this.#bailout) break;
                    if (this.dead) break;
                    this.walk(this.#stepSize);
                }
                this.dead = true;
            }
            walk(distance, topTail = 0) {
                if (this.#alive[topTail]) {

                    const dir = this.#directions[topTail];
                    const pos = this.#positions[topTail].addNew(dir.scaleNew(distance));
                    const f = field(pos, this.#fieldID, this.#id);

                    const t = vars.grid.getChildAtPosition(pos);

                    let draw = true;

                    let i = -this.#distanceBreak;
                    let a = dir.clone();
                    a.angle -= Math.PI * .5;
                    while (i < this.#distanceBreak) {
                        const p = pos.addNew(a.scaleNew(i));
                        const t = vars.grid.getChildAtPosition(p);
                        if (t === -1 || t === this) {} else {
                            draw = false;
                            break;
                        }
                        i += config.testGridSize;
                    }

                    const dp = this.#distanceProjection;
                    let np = pos.clone();
                    const ndir = dir.clone();
                    for (let i = 0; i < dp; i++) {
                        if (draw === false) break;
                        np.add(ndir.scaleNew(distance));
                        const nf = field(np, this.#fieldID, this.#id);
                        ndir.angle = nf.noise;
                        let j = -this.#distanceBreak*this.#projectionBreakMultiplier;
                        let a = ndir.clone();
                        a.angle -= Math.PI * .5;
                        while (j <= this.#distanceBreak*this.#projectionBreakMultiplier) {
                            const p = np.addNew(a.scaleNew(j));
                            const t = vars.grid.getChildAtPosition(p);
                            if (t === -1 || t === this) {} else {
                                draw = false;
                                break;
                            }
                            j += config.testGridSize;
                        }
                    }

                    if (!f.mask) draw = false;

                    if (draw) {
                        if (topTail === 0) {
                            this.#points.push(pos.clone());
                        } else {
                            this.#points.splice(0, 0, pos.clone());
                        }
                        vars.grid.addChildAtPosition(this, pos);
                        this.#positions[topTail] = pos.clone();
                    } else {
                        this.#alive[topTail] = false;
                    }

                    dir.angle = f.noise;
                    if (topTail === 1) dir.rotate(Math.PI);

                }
                if (topTail === 0 && this.#alive[1]) {
                    this.walk(distance, 1)
                }
            }

            get length() {
                return this.#points.length * this.#stepSize;
            }
            set dead(v) {
                if (v === false) {
                    this.#alive[0] = false;
                    this.#alive[1] = false;
                } else if (v === true) {
                    this.#alive[0] = true;
                }
            }
            get dead() {
                return !this.#alive[0] && !this.#alive[1];
            }
            get points() {
                let points = this.#points;
                if (points.length * this.#stepSize < this.#minLength) {
                    points.forEach((p) => {
                        vars.grid.addChildAtPosition(-1, p);
                    });
                    return null;
                }
                return points.map(p => p.array);
            }
            get bezier() {
                const points = this.points;
                if (!points?.length || points.length <= 1) return;
                const bezierCurves = fitCurve(this.points, 1);
                let str = "";
                bezierCurves.map(function(bezier, i) {
                    if (i == 0) {
                        str += "M " + bezier[0][0] + " " + bezier[0][1];
                    }
                    str += "C " + bezier[1][0] + " " + bezier[1][1] + ", " +
                    bezier[2][0] + " " + bezier[2][1] + ", " +
                    bezier[3][0] + " " + bezier[3][1] + " ";
                });

                return str;
            }
            get id() {
                return this.#fieldID;
            }
            set directionHead(v) {
                if (v instanceof Vec2) this.#directions[0] = v;
            }
            get directionHead() {
                return this.#directions[0];
            }
            set directionTail(v) {
                if (v instanceof Vec2) this.#directions[1] = v;
            }
            get directionTail() {
                return this.#directions[1];
            }
        }


        class Drawing {
            static DT_CANVAS = 1;
            static DT_SVG = 2;
            #drawing;
            #ctx;
            #mode;
            #instructions = [];

            constructor(mode = Drawing.DT_CANVAS) {
                this.mode = mode;
                if (this.mode & Drawing.DT_CANVAS) {
                    this.#drawing = document.createElement('canvas');
                } else if (this.mode & Drawing.DT_SVG) {
                    this.#drawing = SVG();
                }

                this.stroke = '#333';
            }
            clear() {
                if (this.mode & Drawing.DT_CANVAS) {
                    this.c.clearRect(0, 0, ...this.dimensions.array);
                } else if (this.mode & Drawing.DT_SVG) {
                    this.drawing.clear();
                }
            }
            rect(position, dimensions) {
                if (this.saving) {
                    this.#instructions.push({
                        f: 'rect',
                        args: [position, dimensions]
                    });
                }
                if (this.mode & Drawing.DT_CANVAS) {
                    this.c.beginPath();
                    this.c.rect(...position.array, ...dimensions.array);
                    this.c.stroke();
                } else if (this.mode & Drawing.DT_SVG) {
                    this.drawing.rect(dimensions.width, dimensions.height).move(...position.array).fill("none").stroke('#f06');
                }
            }
            circle(position, radius) {
                if (this.saving) {
                    this.#instructions.push({
                        f: 'circle',
                        args: [position, radius]
                    });
                }
                if (this.mode & Drawing.DT_CANVAS) {
                    this.c.beginPath();
                    this.c.arc(position.x, position.y, radius, 0, 2 * Math.PI);
                    if (this.stroke) this.c.stroke();
                } else if (this.mode & Drawing.DT_SVG) {
                    this.drawing.circle(radius*2).fill("none").stroke(this.stroke).move(...position.subtractScalarNew(radius).array);
                }
            }
            line(a, b) {
                if (this.saving) {
                    this.#instructions.push({
                        f: 'line',
                        args: [a, b]
                    });
                }
                if (this.mode & Drawing.DT_CANVAS) {
                    this.c.beginPath();
                    this.c.moveTo(a.x, a.y);
                    this.c.lineTo(b.x, b.y);
                    if (this.stroke) this.c.stroke();
           .........完整代码请登录后点击上方下载按钮下载查看

网友评论0