javascript - 如何填充矩形内的粒子?

标签 javascript canvas html5-canvas

我想画一个基本上是文本的矩形,但只是为了清晰的洞察力,我正在使用矩形内部有小颗粒的矩形来绘制它,这是我从 https://yalantis.com/ 得到的基本想法。但在我的尝试中,我被困在这里,使用我为粒子指定的颜色的实心填充矩形。请帮助我.. :)

谢谢这是我的代码:

<html lang="en">
<head>
<meta charset="UTF-8">
<title>Off Screen Canvas</title>
<script>
    function createOffscreenCanvas() {
        var offScreenCanvas = document.createElement('canvas');
        offScreenCanvas.width = '1360';
        offScreenCanvas.height = '400';
        var context = offScreenCanvas.getContext("2d");
        var W=200;
        var H=200;
        particleCount = 200;
        particles = []; //this is an array which will hold our particles Object/Class
        function Particle() {
            this.x = Math.random() * W;
            this.y = Math.random() * H;
            this.direction ={"x": -1 + Math.random()*2, "y": -1 + Math.random()*2};
            this.vx = 2 * Math.random() + 4 ;
            this.vy = 2 * Math.random() + 4;
            this.radius = .9 * Math.random() + 1;
            this.move = function(){
                this.x += this.vx * this.direction.x;
                this.y += this.vy * this.direction.y;
            };
            this.changeDirection = function(axis){
                this.direction[axis] *= -1;
            };
            this.draw = function() {
                context.beginPath();
                context.fillStyle = "#0097a7";
                context.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
                context.fill();
            };
            this.boundaryCheck = function(){
                if(this.x >= W){
                    this.x = W;
                    this.changeDirection("x");
                }
                else if(this.x <= 0){
                    this.x = 0;
                    this.changeDirection("x");
                }
                if(this.y >= H){
                    this.y = H;
                    this.changeDirection("y");
                }
                else if(this.y <= 0){
                    this.y = 0;
                    this.changeDirection("y");
                }
            };
        }
        function createParticles(){
            for (var i = particleCount-1; i >= 0; i--) {
                p = new Particle();
                particles.push(p);
            }
        }// end createParticles
        function drawParticles(){
            for (var i = particleCount-1; i >= 0; i--){
                p = particles[i];
                p.draw();
            }
        } //end drawParticles

        function updateParticles(){
            for(var i = particles.length - 1; i >=0; i--){
                p = particles[i];
                p.move();
                p.boundaryCheck();

            }
        }//end updateParticle
        createParticles();
        var part=drawParticles();
        context.fillStyle=part;
        context.fillRect(W-190, H-190, W, H);
        context.fill();
        return offScreenCanvas;
    }
    function copyToOnScreen(offScreenCanvas) {
        var onScreenContext=document.getElementById('onScreen').getContext('2d');
        var offScreenContext = offScreenCanvas.getContext('2d');
        var image=offScreenContext.getImageData(10,10,200,200);
        onScreenContext.putImageData(image,offScreenCanvas.width/2,offScreenCanvas.height/4);
    }

    function main() {
        copyToOnScreen(createOffscreenCanvas());
    }
</script>
<style>
    canvas {
        border: 1px solid red;
    }
</style>
</head>
<body onload="main()"> 
<canvas id="onScreen" width="1360" height="400"></canvas>
 </body>
</html>

最佳答案

我发现您还没有找到您要找的东西。下面是一些可以让你快速上手的东西。从 Canvas 、鼠标、粒子等中使用了各种各样的东西,其中大部分都没有评论。没有负载平衡或合规性测试,因为它使用 babel 与 IE11 兼容,所以我不知道它如何在这些浏览器上运行。

我会在其他时间添加到这个答案,但现在我已经有点过了。

const textList = ["1","2","3","Testing","text","to","particles"];
var textPos = 0;
function createParticles(text){
    createTextMap(
        text,  // text to display
        40,    // font size
        "Arial",  // font
        {  // style fot rendering font
            fillStyle : "#6AF",
            strokeStyle : "#F80",
            lineWidth : 2,
            lineJoin : "round",
        },{  // bounding box to find a best fit for
            top : 0,
            left : 0,
            width : canvas.width,
            height : canvas.height,
        }
    )
}
// This function starts the animations
var started = false;
function startIt(){
    started = true;
    const next = ()=>{
        var text = textList[(textPos++ ) % textList.length];
        particles.mouseFX.dist = canvas.height  / 8;
        createParticles(text);
        setTimeout(moveOut,text.length * 100 + 3000);
    }
    const moveOut = ()=>{
        particles.moveOut();
        setTimeout(next,2000);
    }
    setTimeout(next,0);
}


function setStyle(ctx,style){
    Object.keys(style).forEach(key => ctx[key] = style[key]);
}

// the following function create the particles from text using a canvas
// the canvas used is dsplayed on the main canvas top left fro referance.
var tCan = createImage(100, 100); // canvas used to draw text
function createTextMap(text,size,font,style,fit){
    // function to conver to colour hex value
    const hex = (v)=> (v < 16 ? "0" : "") + v.toString(16);
    // set up font so we can find the size.
    tCan.ctx.font = size + "px " + font;
    // get size of text
    var width = Math.ceil(tCan.ctx.measureText(text).width + size);
    // resize the canvas to fit the text
    tCan.width = width;
    tCan.height = Math.ceil(size *1.2);
    // c is alias for context
    var c = tCan.ctx;
    // set up font 
    c.font = size + "px " + font;
    c.textAlign = "center";
    c.textBaseline = "middle";
    // set style
    setStyle(c,style);
    // only do stroke and fill if they are set in styles object
    if(style.strokeStyle){
        c.strokeText(text, width / 2, tCan.height / 2);
    }
    if(style.fillStyle){
        c.fillText(text, width / 2, tCan.height/ 2);
    }
    // prep the particles
    particles.empty();
    // get the pixel data
    var data = c.getImageData(0,0,width,tCan.height).data;
    var x,y,ind,rgb,a;
    // find pixels with alpha > 128
    for(y = 0; y < tCan.height; y += 1){
        for(x = 0; x < width; x += 1){
            ind = (y * width + x) << 2;  // << 2 is equiv to * 4
            if(data[ind + 3] > 128){  // is alpha above half
                rgb = `#${hex(data[ind ++])}${hex(data[ind ++])}${hex(data[ind ++])}`;
                // add the particle
                particles.add(Vec(x, y), Vec(x, y), rgb);
            }
        }
    }
    // scale the particles to fit bounding box
    var scale = Math.min(fit.width / width, fit.height / tCan.height);
    particles.each(p=>{
        p.home.x = ((fit.left + fit.width) / 2) + (p.home.x - (width / 2)) * scale;
        p.home.y = ((fit.top + fit.height) / 2) + (p.home.y - (tCan.height / 2)) * scale;

    })
        .findCenter() // get center used to move particles on and off of screen
        .moveOffscreen()  // moves particles off the screen
        .moveIn();        // set the particles to move into view.

}
// vector object a quick copy from other code.
function Vec(x,y){  // because I dont like typing in new
    return new _Vec(x,y);
}
function _Vec(x = 0,y = 0){
    this.x = x;
    this.y = y;
    return this;
}
_Vec.prototype = {
    setAs(vec){
        this.x = vec.x;
        this.y = vec.y;
    },
    toString(){
        return `vec : { x : ${this.x}, y : ${this.y} );`
    }
}

// basic particle
const particle = {
    pos : null,
    delta : null,
    home : null,
    col : "black",
}
// array of particles
const particles = {
    items : [], // actual array of particles
    mouseFX : {  // mouse FX
        power : 20,
        dist : 100,
        curve : 3, // polynomial power
        on : true,
    },
    fx : {
        speed : 0.4,
        drag : 0.15,
        size : 4,
        jiggle : 8,
    },
    // direction 1 move in -1 move out
    direction : 1,
    moveOut(){this.direction = -1; return this},
    moveIn(){this.direction = 1; return this},
    length : 0, // Dont touch this from outside particles.
    each(callback){ // custom iteration 
        for(var i = 0; i < this.length; i++){
            callback(this.items[i],i);
        }
        return this;
    },
    empty(){ // empty but dont dereference
        this.length = 0;
        return this;
    },
    deRef(){  // call to clear memory
        this.items.length = 0;
        this.length = 0;
    },
    add(pos,home,col){  // adds a particle
        var p;
        if(this.length < this.items.length){
            p = this.items[this.length++];
           // p.pos.setAs(pos);
            p.home.setAs(home);
            p.delta.x = 0;
            p.delta.y = 0;
            p.col = col;
        }else{
            this.items.push(
                Object.assign(
                    {},
                    particle,
                    {
                        pos,
                        home,
                        col,
                        delta : Vec()
                    }
                )
            );
            this.length = this.items.length
        }
        return this;
    },
    draw(){ // draws all
        var p, size, sizeh;
        sizeh = (size = this.fx.size) / 2;
        for(var i = 0; i < this.length; i++){
            p = this.items[i];
            ctx.fillStyle = p.col;
            ctx.fillRect(p.pos.x - sizeh, p.pos.y - sizeh, size, size);
        }
    },
    update(){ // update all particles
        var p,x,y,d;
        var mP = this.mouseFX.power;
        var mD = this.mouseFX.dist;
        var mC = this.mouseFX.curve;
        var fxJ = this.fx.jiggle;
        var fxD = this.fx.drag;
        var fxS = this.fx.speed;

        for(var i = 0; i < this.length; i++){
            p = this.items[i];
            p.delta.x += (p.home.x - p.pos.x ) * fxS + (Math.random() - 0.5) * fxJ;
            p.delta.y += (p.home.y - p.pos.y ) * fxS + (Math.random() - 0.5) * fxJ;
            p.delta.x *= fxD;
            p.delta.y *= fxD;
            p.pos.x += p.delta.x * this.direction;
            p.pos.y += p.delta.y * this.direction;
            if(this.mouseFX.on){
                x = p.pos.x - mouse.x;
                y = p.pos.y - mouse.y;
                d = Math.sqrt(x * x + y * y);
                if(d < mD){
                    x /= d;
                    y /= d;
                    d /= mD;
                    d = (1-Math.pow(d,mC)) * mP;
                    p.pos.x += x * d;
                    p.pos.y += y * d;        
                }
            }
        }
        return this;
    },
    findCenter(){  // find the center of particles maybe could do without
        var x,y;
        y = x = 0;
        this.each(p => {
            x += p.home.x;
            y += p.home.y;
        });
        this.center = Vec(x / this.length, y / this.length);
        return this;
    },
    moveOffscreen(){  // move start pos offscreen
        var dist,x,y;
        dist = Math.sqrt(this.center.x * this.center.x + this.center.y * this.center.y);
        
        this.each(p => {
            var d;
            x = p.home.x - this.center.x;
            y = p.home.y - this.center.y;
            d =  Math.max(0.0001,Math.sqrt(x * x + y * y)); // max to make sure no zeros
            p.pos.x = p.home.x + (x / d)  * dist;
            p.pos.y = p.home.y + (y / d)  * dist;
        });
        return this;
    },
}
function onResize(){  // called from boilerplate
    if(!started){
        startIt();
    }
}

/** SimpleFullCanvasMouse.js begin **/
// the following globals are available
// w, h, cw, ch,  width height centerWidth centerHeight of canvas
// canvas, ctx, mouse, globalTime  

//MAIN animation loop
function display() { // call once per frame
    ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
    ctx.globalAlpha = 1; // reset alpha
    ctx.clearRect(0, 0, w, h);
    if(tCan){
       // ctx.drawImage(tCan,0,0);
    }
    particles.update();
    particles.draw();
    
}




/******************************************************************************
 The code from here down is generic full page mouse and canvas boiler plate 
 code. As I do many examples which all require the same mouse and canvas 
 functionality I have created this code to keep a consistent interface. The
 Code may or may not be part of the answer.
 This code may or may not have ES6 only sections so will require a transpiler
 such as babel.js to run on legacy browsers.
 *****************************************************************************/
// V2.0 ES6 version for Stackoverflow and Groover QuickRun 
var w, h, cw, ch, canvas, ctx, mouse, globalTime = 0;
// You can declare onResize (Note the capital R) as a callback that is also
// called once at start up. Warning on first call canvas may not be at full
// size. 
;(function(){
    const RESIZE_DEBOUNCE_TIME = 100;
    var resizeTimeoutHandle;
    var firstRun = true;
    function createCanvas () {
        var c,cs;
        cs = (c = document.createElement("canvas")).style;
        cs.position = "absolute";
        cs.top = cs.left = "0px";
        cs.zIndex = 1000;
        document.body.appendChild(c);
        return c;
    }
    function resizeCanvas () {
        if (canvas === undefined) { canvas = createCanvas() }
        canvas.width = innerWidth;
        canvas.height = innerHeight;
        ctx = canvas.getContext("2d");
        if (typeof setGlobals === "function") { setGlobals() }
        if (typeof onResize === "function") {
            clearTimeout(resizeTimeoutHandle);
            if (firstRun) { onResize() }
            else { resizeTimeoutHandle = setTimeout(onResize, RESIZE_DEBOUNCE_TIME) }
            firstRun = false;
        }
    }
    function setGlobals () {
        cw = (w = canvas.width) / 2;
        ch = (h = canvas.height) / 2;
    }
    mouse = (function () {
        function preventDefault(e) { e.preventDefault() }
        var m; // alias for mouse
        var mouse = {
            x : 0, y : 0, w : 0, // mouse position and wheel
            alt : false, shift : false, ctrl : false, // mouse modifiers 
            buttonRaw : 0,
            over : false,                        // true if mouse over the element
            buttonOnMasks : [0b1, 0b10, 0b100],  // mouse button on masks
            buttonOffMasks : [0b110, 0b101, 0b011], // mouse button off masks
            active : false,
            bounds : null,
            eventNames : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(","),
            event(e) {
                var t = e.type;
                m.bounds = m.element.getBoundingClientRect();
                m.x = e.pageX - m.bounds.left - scrollX;
                m.y = e.pageY - m.bounds.top - scrollY;
                m.alt = e.altKey;
                m.shift = e.shiftKey;
                m.ctrl = e.ctrlKey;
                if (t === "mousedown") { m.buttonRaw |= m.buttonOnMasks[e.which - 1] }
                else if (t === "mouseup") { m.buttonRaw &= m.buttonOffMasks[e.which - 1] }
                else if (t === "mouseout") { m.over = false }
                else if (t === "mouseover") { m.over = true }
                else if (t === "mousewheel") {m.w = e.wheelDelta }
                else if (t === "DOMMouseScroll") { m.w = -e.detail }
                if (m.callbacks) { m.callbacks.forEach(c => c(e)) }
                if ((m.buttonRaw & 2) && m.crashRecover !== null) {
                    if (typeof m.crashRecover === "function") { setTimeout(m.crashRecover, 0) }
                }
                e.preventDefault();
            },
            addCallback(callback) {
                if (typeof callback === "function") {
                    if (m.callbacks === undefined) {  m.callbacks = [callback] }
                    else { m.callbacks.push(callback) }
                }
            },
            start(element) {
                if (m.element !== undefined) { m.remove() }
                m.element = element === undefined ? document : element;
                m.eventNames.forEach(name =>  document.addEventListener(name, mouse.event) );
                document.addEventListener("contextmenu", preventDefault, false);
                m.active = true;
            },
            remove() {
                if (m.element !== undefined) {
                    m.eventNames.forEach(name => document.removeEventListener(name, mouse.event) );
                    document.removeEventListener("contextmenu", preventDefault);
                    m.element = m.callbacks = undefined;
                    m.active = false;
                }
            }
        }
        m = mouse;
        return mouse;
    })();
    function done() { // Clean up. Used where the IDE is on the same page.
        window.removeEventListener("resize", resizeCanvas)
        mouse.remove();
        document.body.removeChild(canvas);
        canvas = ctx = mouse = undefined;
    }
    function update(timer) { // Main update loop
        if(ctx === undefined){ return }
        globalTime = timer;
        display();           // call demo code
        requestAnimationFrame(update);
    }
    setTimeout(function(){
        canvas = createCanvas(); 
        mouse.start(canvas, true);
        resizeCanvas();
        if(typeof Groover !== "undefined" && Groover.ide){ mouse.crashRecover = done }; // Requires Ace.js and GrooverDev.js. Prevents
        window.addEventListener("resize", resizeCanvas);
        requestAnimationFrame(update);
    },0);
})();
/** SimpleFullCanvasMouse.js end **/
/** CreateImage.js begin **/
// creates a blank image with 2d context
function createImage(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}
/** CreateImage.js end **/
canvas {
   background : black;
}

关于javascript - 如何填充矩形内的粒子?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43406977/

相关文章:

javascript - Backbone 应用组织

javascript - javascript canvas 坦克游戏中的碰撞检测

javascript - 是否有可能 "flip" Canvas 绘图?还有其他解决方法吗?

javascript - 如何隐藏没有给定类集的复选框?

javascript - jEditable InputType 日期?

javascript - 使用 ajax 的甜蜜警报 - 无法弄清楚发布后的返回消息

javascript - 加载未知尺寸的图像并将其居中,保持纵横比和填充

javascript - 你如何计算 Sprite 适合的最小圆形的半径?

javascript - Firefox、Selenium、toDataURL、Uint8ClampedArray 和 Python

javascript - 如何在 HTML5 Canvas 中设置多边形大小的动画?