【问题标题】:How to style canvas elements with CSS如何使用 CSS 设置画布元素的样式
【发布时间】:2015-06-22 21:25:31
【问题描述】:

我在 HTML 画布中绘制了很多图形和元素。它们都有不同的颜色、笔触等。我真的不喜欢所有这些值都在我的 JS 代码中徘徊,因为有些样式在 CSS 中,有些在代码中。

有人知道在 CSS 中定义样式并在实际渲染对象时读取样式的好方法吗?

这是我需要做的一些示例:

context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green'; // I'd like to set with CSS
context.fill();
context.lineWidth = 5; // I'd like to set with CSS
context.strokeStyle = '#003300'; // I'd like to set with CSS
context.stroke();

http://jsfiddle.net/nedyalkov/ysgLqqh3/1/

【问题讨论】:

  • 我也做了一些画布,我认为你不能使用类,因为 Canva 并没有真正做 DOM 元素,但是如果你必须使用多次相同的样式,你可以使用保存/恢复。 an example
  • 虽然 html canvas 是一个 DOM 元素,但它实际上是构成您在画布上绘制的形状的像素的容器。这意味着 CSS 不能影响画布上的形状。如果您想将上下文形状样式与您的应用分开存储,您可以考虑将这些上下文形状样式存储在一个单独的 JSON 文件中,您可以在应用开始时读取该文件。

标签: javascript html css canvas


【解决方案1】:

我参加聚会有点晚了,但我遇到了同样的情况,我这样解决了:

// "Cache"
var classColors = {};

function getColor(className) {
    // Check for the color
    if (!classColors[className]) {

        // Create an element with the class name and add it to the dom
        $c = $('<div class="' + className + '"></div>').css('display', 'none');
        $(document.body).append($c);

        // Get color from dom and put it in the color cache
        classColors[className] = $c.css('color');

        // Remove the element from the dom again
        $c.remove();
    }

    // Return color
    return classColors[className];
}

我只需要颜色,但如果需要,您可以扩展缓存对象以容纳更多颜色。你会从函数中返回一个完整的对象。下面的代码根本没有经过测试:

var classProperties = {};

function getPropeties(className) {
    // Check for the properties object
    if (!classProperties[className]) {

        // Create an element with the class name and add it to the dom
        $c = $('<div class="' + className + '"></div>').css('display', 'none');
        $(document.body).append($c);

        // Get needed stuff from the dom and put it in the cache
        // P.S. Didn't test if canvas names are the same as css names.
        // If not you'll have to translate it
        classProperties[className] = {
            fillStyle: $c.css('color'),
            lineWidth: $c.css('border-width'),
            strokeStyle: $c.css('border-style')
        }

        // Remove the element from the dom again
        $c.remove();
    }

    // Return properties
    return classProperties[className];
}

【讨论】:

  • +1 我很喜欢,毕竟这些好人都说它做不到,你想出了一个非常简单的方法。
  • 这很聪明!
【解决方案2】:

通常,在画布上绘制大量内容的人会制作具有样式属性的自己的形状对象。例如:http://jsfiddle.net/b93cc3ww/

context = document.getElementById("myCanvas").getContext("2d");

function Rectangle(params) {
    this.x = params.x || 0;
    this.y = params.y || 0;
    this.width = params.width || 0;
    this.height = params.height || 0;
    this.fillStyle = params.fillStyle || "#FFFFFF";
    this.strokeStyle = params.strokeStyle || "#000000";
    this.lineWidth = params.lineWidth || 0;
}

Rectangle.prototype.draw = function () {
    if (this.fillStyle) {
        context.fillStyle = this.fillStyle;
        context.fillRect(this.x, this.y, this.width, this.height)
    }
    if (this.strokeStyle && this.lineWidth) {
        context.strokeStyle = this.strokeStyle;
        context.lineWidth = this.lineWidth;
        context.strokeRect(this.x, this.y, this.width, this.height);
    }
}

rectangles = [
    new Rectangle({
        x: 10,
        y: 10,
        width: 300,
        height: 150,
        fillStyle: "#FF0000"
    }),
    new Rectangle({
        x: 250,
        y: 10,
        width: 100,
        height: 80,
        fillStyle: "#00FF00",
        strokeStyle: "#00AA00",
        lineWidth: 5
    }),
    new Rectangle({
        x: 10,
        y: 200,
        width: 250,
        height: 80,
        strokeStyle: "#FF0000",
        lineWidth: 1
    })
]

for (var i = 0; i < rectangles.length; ++i) {
    rectangles[i].draw();
}

如果您喜欢 CSS 的工作方式,您可以创建一个形状对象,该对象可以采用“类”参数,然后将“类”列表存储在代码顶部的数组中。

【讨论】:

  • 这只是对 OP 说的一种迂回方式:“不,你不能这样做。” OP 想要使用实际的 CSS 来渲染画布,而这根本不可能。
  • 在我的实际代码中,我正在做这样的事情 - 我有一些对象代表我的高级绘图对象,并且我在某处有与样式相关的属性,但我希望找到一种方法将样式与逻辑分开,更重要的是——将我所有的颜色、字体和东西放在一个地方。不过,我喜欢你最后的建议——我只需要找到一种方法来获取某个类的所有实际值——DOM 应该有这样的 API。
  • 只是顺便补充一下,如果你要使用这样的东西,不妨利用原型继承。让同一个“类”的所有对象从同一个原型继承它们的样式属性,而不是像我的例子中那样复制它们。
【解决方案3】:

游戏有点晚了,但我认为这仍然很有用,所以我创建了一个已接受答案的 jQuery 免费版本:

var classProperties = {};

function getPropeties(className)
{
  if (true === classProperties[className]) {
    return classProperties[className];
  }

  // Create an element with the class name and add it to the dom
  let element = document.createElement('div');
  element.style.display = 'none;'
  element.classList.add(className);
  document.body.appendChild(element);

  // Get needed stuff from the dom and put it in the cache
  let compStyles = window.getComputedStyle(element);

  classProperties[className] = {
    fill: compStyles.backgroundColor,
    lineWidth: compStyles.borderWidth,
    stroke: compStyles.borderColor
  }
  // Remove the element from the dom again
  element.remove();

  return classProperties[className];
}

另外,因为我遇到了这个问题:如果你想在 Vue 中使用它,你必须等待整个视图被挂载,否则样式有可能由于竞争而无法正确返回计算的样式健康)状况。必要代码见https://vuejs.org/v2/api/#mounted

我敢肯定,在加载 CSS 之前执行任何普通 JS 代码时,这也可能是一个问题。

【讨论】:

    【解决方案4】:

    CSS 对它有一定的作用域,即它只作用于 HTML 元素。另一方面,Javascript 有自己的变量,也可以与 HTML 元素交互。您正在尝试做的是使用 CSS 作为 javascript 的变量,这是无法做到的。

    上面的代码示例代表一段 javascript,它接受一个 HTML 元素(在本例中为 canvas)并对其执行一组操作(方法)。你所做的实际上是一次画一条线来创建你的图像,并且这个图像在 CSS 范围之外,因为它只由元素内部属性定义,而 CSS 只能定义它的外部(特别是视觉)属性。

    【讨论】:

    • “如果一个口渴的人正在寻找水并向右看,但你知道水在左边,告诉他们向左看是很好的。”换句话说,CSS 不是最好的工具,但告诉提问者他们可以在哪里找到他们的解决方案(JS)比告诉他们“那里没有水”来回答更友好。顺便说一句,Firefox 提供 CSS 变量:developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables。我们可以希望它会被更广泛地采用:-)
    • 是的,我明白 CSS 不会以某种方式自动应用于我绘制的图形。我只想将所有东西的样式与其逻辑(呈现对象的 JS 代码)分开。 @markE 不幸的是,我需要一些适用于所有浏览器的解决方案:)
    • @MiroslavNedyalkov,在这种情况下通常使用的样式解决方案是将样式定义放在应用程序随附的 JSON 文件中。这样,您可以在必要时为每个客户定制样式。 ;-)
    • @markE 这听起来很合理,但这样我就可以只为每个客户端自定义部分属性。当然,这是完全不同的故事 :) 我会付出更多努力寻找解决方案,如果找不到合理的解决方案,我可能会坚持使用 JSON 方法。
    • @markE,OP 正在寻求做一些无法做到的非常具体的事情。我想你可以提供一个不同的解决方案,但由于他要求的东西如此具体,它似乎并不合适。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-12
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 2011-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多