md77
md77

Reputation: 31

Trying to add colour gradient to Canvas Text

I am trying to add a colour gradient to the canvas text in this code but nothing I've tried works.

I am new to this so am having difficulties finding the solution.

Is this effect even possible? I have found the code to change the text colour using ctx.fillStyle = gradient;

but it doesn't seem to be working. I'm not even sure where to insert it.

Does anyone know how to achieve this?

window.onresize = function() {
  resize();
  return true;
};
var pixels = []
var canv = $('canv')
var ctx = canv.getContext('2d')
var wordCanv = $('wordCanv')
var wordCtx = wordCanv.getContext('2d')
var mx = -1
var my = -1
var words = ''
var txt = []
var cw = 0
var ch = 0
var resolution = 1
var n = 0
var timerRunning = false
var resHalfFloor = 0
var resHalfCeil = 0
var width = 600
var height = 600

function canv_mousemove(evt) {
  mx = evt.clientX - canv.offsetLeft
  my = evt.clientY - canv.offsetTop
}

function Pixel(homeX, homeY) {
  this.homeX = homeX
  this.homeY = homeY

  this.x = Math.random() * cw
  this.y = Math.random() * ch

  this.xVelocity = Math.random() * 10 - 5
  this.yVelocity = Math.random() * 10 - 5
}

Pixel.prototype.move = function() {
  var homeDX = this.homeX - this.x
  var homeDY = this.homeY - this.y
  var homeDistance = Math.sqrt(Math.pow(homeDX, 2) + Math.pow(homeDY, 2))
  var homeForce = homeDistance * 0.01
  var homeAngle = Math.atan2(homeDY, homeDX)

  var cursorForce = 0
  var cursorAngle = 0

  if (mx >= 0) {
    var cursorDX = this.x - mx
    var cursorDY = this.y - my
    var cursorDistanceSquared = Math.pow(cursorDX, 2) + Math.pow(cursorDY, 2)
    cursorForce = Math.min(10000 / cursorDistanceSquared, 10000)
    cursorAngle = Math.atan2(cursorDY, cursorDX)
  } else {
    cursorForce = 0
    cursorAngle = 0
  }

  this.xVelocity +=
    homeForce * Math.cos(homeAngle) + cursorForce * Math.cos(cursorAngle)
  this.yVelocity +=
    homeForce * Math.sin(homeAngle) + cursorForce * Math.sin(cursorAngle)

  this.xVelocity *= 0.92
  this.yVelocity *= 0.92

  this.x += this.xVelocity
  this.y += this.yVelocity
}

function $(id) {
  return document.getElementById(id)
}

function timer() {
  if (!timerRunning) {
    timerRunning = true
    setTimeout(timer, 33)
    for (var i = 0; i < pixels.length; i++) {
      pixels[i].move()
    }

    drawPixels()
    n++
    if (
      n % 10 == 0 &&
      (cw != width || ch != height)
    )
      body_resize()
    timerRunning = false
  } else {
    setTimeout(timer, 5)
  }
}

function drawPixels() {
  var imageData = ctx.createImageData(cw, ch)
  var actualData = imageData.data

  var index
  var goodX
  var goodY
  var realX
  var realY

  for (var i = 0; i < pixels.length; i++) {
    goodX = Math.floor(pixels[i].x)
    goodY = Math.floor(pixels[i].y)

    for (
      realX = goodX - resHalfFloor; realX <= goodX + resHalfCeil && realX >= 0 && realX < cw; realX++
    ) {
      for (
        realY = goodY - resHalfFloor; realY <= goodY + resHalfCeil && realY >= 0 && realY < ch; realY++
      ) {
        index = (realY * imageData.width + realX) * 4
        actualData[index + 3] = 255
      }
    }
  }

  imageData.data = actualData
  ctx.putImageData(imageData, 0, 0)
}

function readWords() {
  var randomWords = ['Text goes here', 'Text 2 goe ']
  words = item = randomWords[Math.floor(Math.random() * randomWords.length)]
  txt = words.split('\n')
}

function init() {
  readWords()
  var fontSize = 100
  var wordWidth = 0
  do {
    wordWidth = 0
    fontSize -= 5
    wordCtx.font = fontSize + 'px sans-serif'
    for (var i = 0; i < txt.length; i++) {
      var w = wordCtx.measureText(txt[i]).width
      if (w > wordWidth) wordWidth = w
    }
  } while (wordWidth > cw - 50 || fontSize * txt.length > ch - 50)
  wordCtx.clearRect(0, 0, cw, ch)
  wordCtx.textAlign = 'center'
  wordCtx.textBaseline = 'middle'

  for (var i = 0; i < txt.length; i++) {
    wordCtx.fillText(
      txt[i],
      cw / 2,
      ch / 2 - fontSize * (txt.length / 2 - (i + 0.5))
    )
  }

  var index = 0

  var imageData = wordCtx.getImageData(0, 0, cw, ch)
  for (var x = 0; x < imageData.width; x += resolution) {
    for (var y = 0; y < imageData.height; y += resolution) {
      i = (y * imageData.width + x) * 4

      if (imageData.data[i + 3] > 128) {
        if (index >= pixels.length) {
          pixels[index] = new Pixel(x, y)
        } else {
          pixels[index].homeX = x
          pixels[index].homeY = y
        }
        index++
      }
    }
  }

  pixels.splice(index, pixels.length - index)
}

function body_resize() {
  cw = width
  ch = height
  canv.width = cw
  canv.height = ch
  wordCanv.width = cw
  wordCanv.height = ch
  init()
}

resHalfFloor = Math.floor(resolution / 2)
resHalfCeil = Math.ceil(resolution / 2)

body_resize()
timer()
setInterval(init, 3000)
<canvas id="wordCanv" width="100%" height="600px" style="border:10px solid rgb(255,255,255);display:none;">
</canvas>
<canvas id="canv" onmousemove="canv_mousemove(event);" onmouseout="mx=-1;my=-1;" width="100%" height="600px">
</canvas>

Upvotes: 3

Views: 140

Answers (1)

Helder Sepulveda
Helder Sepulveda

Reputation: 17574

It is not clear what kind of gradient effect you want to achieve...
So I guess that any will get you moving, see code below

I just added this:
actualData[index + 1] = realX % 255
in your function drawPixels

Play with those values until you get the desired combination
I'm assuming you are familiar with ImageData if not read more here:

var pixels = []
var canv = $('canv')
var ctx = canv.getContext('2d')
var wordCanv = $('wordCanv')
var wordCtx = wordCanv.getContext('2d')
var mx = -1
var my = -1
var words = ''
var txt = []
var cw = 0
var ch = 0
var resolution = 1
var n = 0
var timerRunning = false
var resHalfFloor = 0
var resHalfCeil = 0
var width = 560
var height = 200

function canv_mousemove(evt) {
  mx = evt.clientX - canv.offsetLeft
  my = evt.clientY - canv.offsetTop
}

function Pixel(homeX, homeY) {
  this.homeX = homeX
  this.homeY = homeY

  this.x = Math.random() * cw
  this.y = Math.random() * ch

  this.xVelocity = Math.random() * 10 - 5
  this.yVelocity = Math.random() * 10 - 5
}

Pixel.prototype.move = function() {
  var homeDX = this.homeX - this.x
  var homeDY = this.homeY - this.y
  var homeDistance = Math.sqrt(Math.pow(homeDX, 2) + Math.pow(homeDY, 2))
  var homeForce = homeDistance * 0.01
  var homeAngle = Math.atan2(homeDY, homeDX)

  var cursorForce = 0
  var cursorAngle = 0

  if (mx >= 0) {
    var cursorDX = this.x - mx
    var cursorDY = this.y - my
    var cursorDistanceSquared = Math.pow(cursorDX, 2) + Math.pow(cursorDY, 2)
    cursorForce = Math.min(10000 / cursorDistanceSquared, 10000)
    cursorAngle = Math.atan2(cursorDY, cursorDX)
  } else {
    cursorForce = 0
    cursorAngle = 0
  }

  this.xVelocity +=
    homeForce * Math.cos(homeAngle) + cursorForce * Math.cos(cursorAngle)
  this.yVelocity +=
    homeForce * Math.sin(homeAngle) + cursorForce * Math.sin(cursorAngle)

  this.xVelocity *= 0.92
  this.yVelocity *= 0.92

  this.x += this.xVelocity
  this.y += this.yVelocity
}

function $(id) {
  return document.getElementById(id)
}

function timer() {
  if (!timerRunning) {
    timerRunning = true
    setTimeout(timer, 33)
    for (var i = 0; i < pixels.length; i++) {
      pixels[i].move()
    }

    drawPixels()
    n++
    if (
      n % 10 == 0 &&
      (cw != width || ch != height)
    )
      body_resize()
    timerRunning = false
  } else {
    setTimeout(timer, 5)
  }
}

function drawPixels() {
  var imageData = ctx.createImageData(cw, ch)
  var actualData = imageData.data

  var index
  var goodX
  var goodY
  var realX
  var realY

  for (var i = 0; i < pixels.length; i++) {
    goodX = Math.floor(pixels[i].x)
    goodY = Math.floor(pixels[i].y)

    for (
      realX = goodX - resHalfFloor; realX <= goodX + resHalfCeil && realX >= 0 && realX < cw; realX++
    ) {
      for (
        realY = goodY - resHalfFloor; realY <= goodY + resHalfCeil && realY >= 0 && realY < ch; realY++
      ) {
        index = (realY * imageData.width + realX) * 4
        
        actualData[index + 1] = realX % 255    
        actualData[index + 3] = 255
      }
    }
  }

  imageData.data = actualData
  ctx.putImageData(imageData, 0, 0)
}

function readWords() {
  var randomWords = ['Text 4 foo ', 'Text 2 goe ']
  words = item = randomWords[Math.floor(Math.random() * randomWords.length)]
  txt = words.split('\n')
}

function init() {
  readWords()
  var fontSize = 80
  var wordWidth = 0
  wordCtx.font = fontSize + 'px sans-serif'
  do {
    wordWidth = 0
    fontSize -= 10
    
    for (var i = 0; i < txt.length; i++) {
      var w = wordCtx.measureText(txt[i]).width
      if (w > wordWidth) wordWidth = w
    }
  } while (wordWidth > cw - 50 || fontSize * txt.length > ch - 50)
  wordCtx.clearRect(0, 0, cw, ch)
  wordCtx.textAlign = 'center'
  wordCtx.textBaseline = 'middle'

  for (var i = 0; i < txt.length; i++) {
    wordCtx.fillText(
      txt[i],
      cw / 2,
      ch / 2 - fontSize * (txt.length / 2 - (i + 0.5))
    )
  }

  var index = 0

  var imageData = wordCtx.getImageData(0, 0, cw, ch)
  for (var x = 0; x < imageData.width; x += resolution) {
    for (var y = 0; y < imageData.height; y += resolution) {
      i = (y * imageData.width + x) * 4

      if (imageData.data[i + 3] > 128) {
        if (index >= pixels.length) {
          pixels[index] = new Pixel(x, y)
        } else {
          pixels[index].homeX = x
          pixels[index].homeY = y
        }
        index++
      }
    }
  }

  pixels.splice(index, pixels.length - index)
}

function body_resize() {
  cw = width
  ch = height
  canv.width = cw
  canv.height = ch
  wordCanv.width = cw
  wordCanv.height = ch
  init()
}

resHalfFloor = Math.floor(resolution / 2)
resHalfCeil = Math.ceil(resolution / 2)

body_resize()
timer()
setInterval(init, 3000)
<canvas id="wordCanv" width="100%" height="200px" style="display:none;">
</canvas>
<canvas id="canv" width="100%" height="200px">
</canvas>

Upvotes: 1

Related Questions