什么方法最适合构建这个复杂的图形

时间:2011-05-27 14:10:04

标签: php javascript css user-interface charts

在做UI开发15年后,我很少看到并思考,“我到底怎么做。”这是其中一次。

一位平面设计师将我的客户卖给了一个非常复杂的五边形图形,由五个单独的三角形组成。设计者已指定每个三角形应为与品牌匹配的特定颜色,并且每个三角形应根据每种颜色所代表的过程百分比“填充”。你几乎要看到图像才能理解: enter image description here

我一直绞尽脑汁想要找出如何完成这项任务的一天。客户端已经指定它必须在所有主流浏览器中兼容,为了理智,我将告诉他将是IE7 +。这严重限制了CSS3技术,但由于缺乏其他想法,我肯定会接受CSS3方法。我不想在动作脚本上熬夜,所以Flash是我愿望清单的最底层。我实际上已经使用Sprites集思广益,但是制作250或500个三角形以及相关CSS的想法正在与IE6交易Chrome进行排名。

该网站建立在PHP / MySQL之上,我们大量使用Jquery。如有必要,我们还可以提供完整版的FusionCharts和HighCharts。如果有可以实现这一目标的商业产品,我当然愿意购买它来实现这一目标。

实现这项艰巨任务的最佳方法是什么?

5 个答案:

答案 0 :(得分:27)

除非我找到已经编写的实现,否则我会使用Raphaël

这需要大量工作,但最终结果应该非常好。

看看一些演示,它们非常光滑。

  

Raphaël目前支持Firefox   3.0 +,Safari 3.0 +,Chrome 5.0 +,Opera 9.5+和Internet Explorer 6.0 +。


这看起来很有趣,所以我决定用Raphaël自己实现它:

请参阅: http://jsfiddle.net/2Tsjy/

它应该在“所有浏览器”中工作。我没有做的唯一部分是文本。

<强> JavaScript的:

var paper = Raphael("pentagon"),
    fullNum = [40, 53],
    borderColours = ['#329342','#9e202c','#f47933','#811f5a','#11496c'],
    fillColours = ['#74ae3d','#d01f27','#eaa337','#32133f','#2c7aa1'],
    triangles = [],
    border, fill, st, i;

for (i=0; i<5; i++) {
    border = paper.path(getPercentPath(0)).attr({
        'fill': borderColours[i],
        'stroke-width': 0        
    }),
    fill = paper.path(["M", 116, 123] + "l-44,61 88,0z").attr({
        'stroke': fillColours[i],
        'stroke-width': 6
    });
    triangles.push(border);

    st = paper.set();
    st.push(border, fill);
    st.rotate(i * 72, 116, 113);

    setPercent(i, 30+Math.floor(Math.random()*70));
}

function getPercentPath(percent) {
    var ratio = percent/100;
    return ["M", 116, 128] + "l-" + ratio*fullNum[0] + "," + ratio*fullNum[1] + " " + ratio*fullNum[0]*2 + ",0z";
}
function setPercent(i, percent) {
    triangles[i].attr({
        path: getPercentPath(percent)
    });
}


setInterval(function(){
    for (var i=0; i<5; i++) {
        setPercent(i, 30+Math.floor(Math.random()*70));
    }
}, 2000);

<强> CSS:

#pentagon {
    width: 226px;
    height: 227px;
    border: 1px solid red;
    background: #fff;
    background: rgba(255,255,255,0.8)
}

<强> HTML:

<div id="pentagon"></div>

答案 1 :(得分:7)

我必须推荐RaphaelJS(见http://raphaeljs.com/)。它与IE7兼容,你可以很好地完成三角形:你需要做数学,但很有可能。

编辑:查看http://www.chittram.com/editor.jsp,了解一些可以完成的形状的快速示例。该网站是一个交互式编辑器,但展示了您所需的核心功能。

答案 2 :(得分:7)

<canvas>怎么样? 您可以轻松地绘制一个三角形,然后通过旋转画布360/5度来绘制其他三角形。

示例:http://jsfiddle.net/Stijntjhe/dC6kX/

window.onload = function() {
    var ce = document.getElementById('ce');
    var c = ce.getContext('2d');
    c.translate(ce.offsetWidth / 2, ce.offsetHeight / 2);

    for(var pie = 0; pie < 5; pie++) {
        c.save();
        c.rotate(pie/5 * Math.PI * 2);

        c.beginPath();
        c.moveTo(0, -10);
        c.lineTo(-50, -80);
        c.lineTo(50, -80);
        c.lineTo(0, -10);
        c.lineWidth = 5;
        c.lineCap = 'square';
        c.strokeStyle = colors[pie];
        c.stroke();

        c.restore();
    } 
}

变为:

enter image description here

缺点: 也许还没有跨浏览器。

答案 3 :(得分:4)

如果它必须尽可能兼容,我会生成一个SVG图像并将其渲染为PNG。对于像这样的图像来说,这几乎没有那么慢点。

这是一个非常快速,非常脏的例子。它假设您有ImageMagick扩展名可用,但您可以将SVG转储到文件中,并exec()使用命令行工具rsvg。显然,“正确”的答案涉及渲染图的某种缓存方案。另外,请原谅我不再是SVG忍者。

<强> graph.svg.php:

<?php echo '<'; ?>?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="240" height="240"
     xmlns="http://www.w3.org/2000/svg" version="1.1">

  <g transform="translate(120,120) translate(0,15)">
    <polygon fill="none" stroke="green" stroke-width="10" 
              points="0,0 -50,68.82 50,68.82" />
    <g transform="scale(<?php echo $fill['green']; ?>)">
      <polygon fill="green" stroke="green" stroke-width="10" 
                points="0,0 -50,68.82 50,68.82" />
    </g>
  </g>

  <g transform="translate(120,120) rotate(72) translate(0,15)">
    <polygon fill="none" stroke="red" stroke-width="10" 
              points="0,0 -50,68.82 50,68.82" />
    <g transform="scale(<?php echo $fill['red']; ?>)">
      <polygon fill="red" stroke="red" stroke-width="10" 
                points="0,0 -50,68.82 50,68.82" />
    </g>
  </g>

  <g transform="translate(120,120) rotate(144) translate(0,15)">
    <polygon fill="none" stroke="yellow" stroke-width="10" 
              points="0,0 -50,68.82 50,68.82" />
    <g transform="scale(<?php echo $fill['yellow']; ?>)">
      <polygon fill="yellow" stroke="yellow" stroke-width="10" 
                points="0,0 -50,68.82 50,68.82" />
    </g>
  </g>

  <g transform="translate(120,120) rotate(216) translate(0,15)">
    <polygon fill="none" stroke="purple" stroke-width="10" 
              points="0,0 -50,68.82 50,68.82" />
    <g transform="scale(<?php echo $fill['purple']; ?>)">
      <polygon fill="purple" stroke="purple" stroke-width="10" 
                points="0,0 -50,68.82 50,68.82" />
    </g>
  </g>

  <g transform="translate(120,120) rotate(288) translate(0,15)">
    <polygon fill="none" stroke="blue" stroke-width="10" 
              points="0,0 -50,68.82 50,68.82" />
    <g transform="scale(<?php echo $fill['blue']; ?>)">
      <polygon fill="blue" stroke="blue" stroke-width="10" 
                points="0,0 -50,68.82 50,68.82" />
    </g>
  </g>

</svg>

<强> render.php:

<?php

$fill = array(
    'green'  => 0.5,
    'red'    => 0.8,
    'yellow' => 0.55,
    'purple' => 0.4,
    'blue'   => 0.75,
);

ob_start();
include('graph.svg.php');
$svg = ob_get_contents();
ob_end_clean();

$im = new Imagick();
$im->readImageBlob($svg);
$im->setImageFormat('png24');
$png = $im->getImagesBlob();
$im->clear();
$im->destroy();

header('Content-Type: image/png');
header('Content-Length: ' . strlen($png));
echo $png;
exit;

输出如下:

Rendered graph

答案 4 :(得分:2)

我认为如果你不得不在JS / CSS和Flash / HTML5中做到这一点,那么看看在CSS中使用三角形的方便技巧:

http://www.howtocreate.co.uk/tutorials/css/slopes

另一个参考:

http://css-tricks.com/snippets/css/css-triangle/

通过巧妙地设置框的边框厚度,您可以在任何旋转时获得所需的任何形状三角形。想弄清楚是很棘手的,我没有代码方便,但它是可能的。

你可以在彼此之间嵌套三角形(看样本图片我注意它完全由三角形组成,内三角形是外三角形的倒置巢)所以我认为这是完全可能的,尽管数学可能会有点在定位方面很棘手,如果你需要图表灵活(任意数量的三角形和大小)。