HT for Web首创的矢量图片设计架构,使其具备强大丰富的动态图形呈现能力,但从最近知乎热议的“Adobe Photoshop 是否已通过时?”的话题,你们能体会到不少状况下实际项目不可能彻底采用矢量,项目中仍是有大量的传统非矢量的静态图片,毕竟工具强大且现有资源丰富,但为了使静态图片呈现出更多的动态效果,HT for Web提供了较多渲染方式,例如对HT for Web的图元设置‘body.color’的style后图元便可达到自动染色的效果,这里将对这种染色技术进行讲解。html
上图呈现了本文例子最终的呈现效果,中间为原始图片是http://hightopo.com/images/banner.png ,对其分别设置了红、黄和蓝三种颜色后的染色效果,彻底基于HT for Web实现这么个简单拓扑的话代码不过十多行,不过今天咱们不借助HT for Web提供的‘body.color’的染色功能,咱们将采用最原始的方式生产染色图片。node
dataModel = new ht.DataModel(); graphView = new ht.graph.GraphView(dataModel); graphView.addToDOM(); var root = new ht.Node(); root.setImage('ht-for-web.png'); dataModel.add(root); ['blue', 'yellow', 'red'].forEach(function(color){ var node = new ht.Node(); node.setImage('ht-for-web.png'); node.s({ 'body.color': color }); dataModel.add(node); var edge = new ht.Edge(root, node); edge.s({'edge.color': color}); dataModel.add(edge); });
染色的原理就是对图片像素内容的操做,能够理解为一个 convertColor(r, c, rawColor, …)->finalColor 的像素函数转换, 其中的r和c分别表明像素所在行和列,rawColor为原始颜色信息,…表明其余的参数信息,例如咱们进行染血的颜色信息,最终经过convertColor处理返回的finalColor为转换后的像素值。web
图片染色操做能够说是最简单的图像处理了,本质就是rawColor * tintColor,这里的tintColor能够理解为HT for Web的body.color值,通常该信息表明监控系统的告警级别状态等信息,经过染色让用户更直观的观察到设备运行告警状态。这里的rawColor * tintColor相乘是本质是分别对两个颜色的rgb进行相乘,通常状况下最后的alpha的透明度,会保持原始rawColor的值不进行操做处理。算法
toRGBA = (function(){ var map = {}, // string - [128,128,128,255] canvas; return function(color){ var g, data = map[color]; if (!data) { if(!canvas){ canvas = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; } g = canvas.getContext('2d'); g.clearRect(0, 0, 1, 1); g.fillStyle = color; g.beginPath(); g.rect(0, 0, 1, 1); g.fill(); data = g.getImageData(0, 0, 1, 1).data; data = map[color] = [data[0], data[1], data[2], data[3]]; } return data; }; })(); function init(){ var image = new Image(); image.src = 'banner.png';// 'ht-for-web.png'; image.onload = function(){ dataModel = new ht.DataModel(); graphView = new ht.graph.GraphView(dataModel); graphView.addToDOM(); var root = new ht.Node(); root.setImage(image); dataModel.add(root); ['blue', 'yellow', 'red'].forEach(function(color){ var node = new ht.Node(); node.setImage(createColorImage1(image, color)); dataModel.add(node); var edge = new ht.Edge(root, node); edge.s({ 'edge.color': color }); dataModel.add(edge); }); }; } function createColorImage1(image, color) { var width = image.width; var height = image.height; var canvas = document.createElement('canvas'); var context = canvas.getContext( "2d" ); canvas.width = width; canvas.height = height; context.drawImage(image, 0, 0, width, height); var rgba = toRGBA(color); var r = rgba[0]/255, g = rgba[1]/255, b = rgba[2]/255; var pixelData = context.getImageData(0, 0, width, height); var pixels = pixelData.data; for (var i = 0; i < pixels.length; i += 4) { pixels[i+0] *= r; pixels[i+1] *= g; pixels[i+2] *= b; } context.putImageData(pixelData, 0, 0); return canvas; }
以上代码为实现的所有逻辑,有两点须要注意,颜色值经过getImageData返回的是0~255的值,进行染色相乘咱们须要基于0~1的格式,所以须要先除以255转换后再相乘。另一点为了方便用户开发,颜色值容许是任意html支持的颜色格式,有可能输入red,rgba(255,125,128,0.1)等格式,以上toRGBA代码在闭包中返回了个可根据输入格式返回颜色数组的工具函数,其借助的也是在一个像素的canvas内存中动态绘制,再经过getImageData来决定颜色信息,再经过map缓存计算结果,这种方式比枚举一堆颜色映射表来得精简。canvas
固然采用这种染色算法在图元是纯黑色的时候是有问题的,由于黑色的rgb值都为0,所以不管乘以什么颜色结果也都为0,实际应用场景能够要求美工避免作纯黑色的图片,或者代码对纯黑色的图片进行特殊的运算处理。数组
以上方式仅是第一种染色方式,所以为createColorImage1,下篇将介绍第二种染色方式createColorImage2。缓存