尝试向画布文本添加颜色渐变

3

我试图给这段代码中的画布文本添加颜色渐变,但是我尝试过的所有方法都不起作用。

由于我是新手,所以很难找到解决办法。

这种效果是否可能?我已经找到了可以通过使用ctx.fillStyle = gradient;更改文本颜色的代码

但它似乎没有起作用。我甚至不确定应该在哪里插入它。

有人知道如何实现这一点吗?

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>

1个回答

1

目前不清楚您想要实现什么样的渐变效果...
所以我猜任何一种都可以让您开始动手,参见下面的代码

我只是在您的函数drawPixels中添加了这个:
actualData[index + 1] = realX % 255

尝试调整这些值,直到获得所需的组合
我假设您熟悉ImageData,如果不熟悉,请在此处阅读更多:

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>


嗨,Helder,谢谢你的回复,也非常感谢你的答案。我想我应该更明确地说明我想要实现什么。期望的效果是一个类似于这个链接中的循环彩虹效果:https://www.html5canvastutorials.com/advanced/html5-cavas-rotating-rainbow-text-effect/我还是很新手,很多东西超出了我的理解范围,不知道如何组合代码并进行有效的更改。非常感谢你的帮助。 - md77
@md77 当然可以做到...现在你知道关键是在actualData上设置颜色值,所以你应该能够做到...但你必须尝试一下,在你的一面展示一些努力。 - Helder Sepulveda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接