阿鹏 细说highmaps

最近发现用highmaps的用户越来越多,都分分加入到QQ群和微信来咨询我 (容我打个广告,鹏吧技术群:86031665,(^__^) ),之前写过一篇highmaps的文章,没看过的,请移步至 如何使用highmaps,点击此处传送门 ,那么今天又写这篇文章的目的是综合了许多朋友的疑问,为大家在详细说下highmaps的一些具体用法和细节问题。

疑问

基本大家提的最多的问题如下:

  • 如何正确引用highmaps文件?
  • 如何给highmaps初始化赋值及钻取城市赋值?
  • 如何点击省份向下钻取?
  • 如何给向下钻取的城市动态添加点击事件?
  • 如何点击省份后不是向下钻取,而是在其右侧独立展示省份的地图?

带着这些疑问我下面就为大家具体谈谈。。。

查看更多

highstock 新属性及进阶用法

highstock V2.19 新属性介绍

ordinal :In an ordinal axis, the points are equally spaced in the chart regardless of the actual time or x distance between them. This means that missing data for nights or weekends will not take up space in the chart. Defaults to true.

以上是官方给出的解释,大概说的什么意思呢,用我自己的话理解就是 “在X轴上所有的点都是按时间或者距离等比分配的,这就意味着没有出现的点或者后来延迟加进来的点不会占用掉x轴上的位置和空间”,接下来我们就通过例子和demo讲解。

之前我写过一篇文章highstock分时图的开发,里面提到了这个问题,我们重新回顾一遍,在分时图的开发中,例如我们需要显示的是 早上 8:00到晚上20:00的数据,X轴每隔两小时显示一个label,若当前时间为9点,那么我们需要向服务端拿到8点至15点的数据,那么问题来了,我们会发现图表展示出来整个x轴就是8点到15点,而剩余15点到20点的x轴label并没有占得空间和位置,如下图所示:

查看更多

热点图的深入分析(2)

为了阅读的连续性,我还是尽快把《热点图的深入分析(2)》 写了,不然感觉会被大家嫌弃,没看(1)的小伙伴我送上地址:传送门

上一篇给大家介绍了热点图数据的收集,那这篇主要是给大伙讲解如何展现,就直接步入正题了


如何动态载入网页

我们需要将原始的网页加载到iframe中,然后用一个遮罩层盖住这个iframe,最后用canvas绘制出热图覆盖在这个上面。

1
2
3
4
5
6
7
8
9
<div id="overflowDiv">
<div id="heatmapArea">
<div id="maskDiv">
</div>
<p>
<iframe src="" id="webPageFrame" frameborder="0" name="webPageFrame" scrolling="no" width="1280"></iframe>
</p>
</div>
</div>

查看更多

创建 .bowerrc 文件 , 使用代理下载资源

最近学习reactjs,利用bower去管理相关的资源文件。但中途出现一个问题,由于我们本地办公电脑本身就是使用的代理才能上网,因此不能直接使用bower去下载插件。

于是在网上查找了一些方法,需要设置bower的代理,此时我们需要一个文件.bowerrc。需要在这个文件里配置相关的代理设置。开始以为.bowerrc 是一个 xxx.bowerrc 后缀的一个文件,于是在目录下手动建了一个类似的文件,发现没有用。

后来又搜寻一番,发现可以通过cmd命令去创建文件,于是试了一把果然成功了。分享给大伙,免得和我有一样遭遇的小伙伴烦恼

最后用任意编辑器打开 .bowerrc ,输入以下代理设置

1
2
3
4
{
"proxy": "http://192.168.20.6:3128",
"https-proxy": "http://192.168.20.6:3128"
}

大功告成,可以下载想要的东西啦

如何将phantomjs单独部署在服务端

hey,every one ,很久没给大家分享技术型的文章啦,今天抽时间来一发吧

一. 容我分析(lao dao)几句

之前写了2篇 highcharts 结合 phantomjs 后端生成图片的文章,
http://www.peng8.net/2014/07/21/render-charts-serverside/
http://www.peng8.net/2014/11/24/highchart-table-export-image-by-phantomjs/
第一篇呢,纯后端生成,动态生成json,并将json存在文件中,后端调用phantomjs.exe ,将生成的json文件传入 phantomjs 中。
第二篇呢,是通过前端触发,将页面上的渲染出来的图表和TABLE 整个一起生成一张图片,其实这种也可以放在后端执行。
以上2种方式,都会有个缺点,就是当生成的图片很多,或者请求页面很多时,我们要重复一次一次的去调用phantomjs.exe这个玩意,耗内存,耗时间,直到昨天突然有个群里的人问我,在服务端单独部署一个phantomjs.exe ,开启一个端口,它一直运行着,只要有请求发向它,它就生成一个base64的字符串返回回来,其实官方已经提供了将phantomjs.exe单独部署的方法,于是我研究了一番,最后分享给大家。好了,唠叨结束,接下来我们看看是如何实现的?

二. 服务端 Look here

我用.NET新建一个解决方案,里面包含了2个项目,一个web项目,另外一个是winform项目,当然你也可以弄2个web项目,不影响部署。

<1> 服务端phantomjs搭建

  1. 一些准备文件
    phantomjs.exehighcharts工具包
  2. winform界面写出来
    服务界面
  3. winform后端核心代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #region 启动进程
    Process p = new Process();
    p.StartInfo.FileName = Environment.CurrentDirectory + "//phantomjs//phantomjs_1.9V.exe";

    string ExcuteArg = Environment.CurrentDirectory + "//script//highcharts-convert.js -host 127.0.0.1 -port 3003";
    p.StartInfo.Arguments = string.Format(ExcuteArg);
    p.StartInfo.CreateNoWindow = false;
    p.StartInfo.UseShellExecute = false;
    //重定向标准输出
    p.StartInfo.RedirectStandardOutput = true;
    //重定向错误输出
    p.StartInfo.RedirectStandardError = false; ;
    p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
    string[] result = { };
    if (!p.Start())
    {
    throw new Exception("无法启动Headless测试引擎.");
    }

    result = p.StandardOutput.ReadToEnd().Split(new char[] { '\r', '\n' });
    if (result.Length == 0)
    {
    result[0] = "已成功启动,但无数据";
    }
    foreach (string s in result)
    {
    list_Msg.Items.Add(s);
    }
    #endregion

<2> web端搭建及如何调用phantomjs

  1. web页面搭建
    web界面
    实际上这个步骤可以省略,只是为了展示返回的数据而已,毕竟可以纯后端生成。
  2. 向phantomjs 发起post请求的核心代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    private string HttpPostNew(string Url, string postDataStr)
    {
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = Encoding.UTF8.GetByteCount(postDataStr);

    Stream myRequestStream = request.GetRequestStream();
    StreamWriter myStreamWriter = new StreamWriter(myRequestStream, Encoding.GetEncoding("gb2312"));
    myStreamWriter.Write(postDataStr);
    myStreamWriter.Close();

    HttpWebResponse response;
    try
    {
    response = (HttpWebResponse)request.GetResponse();
    }
    catch (WebException ex)
    {
    response = (HttpWebResponse)ex.Response;
    }
    Stream myResponseStream = response.GetResponseStream();
    StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
    string retString = myStreamReader.ReadToEnd();
    myStreamReader.Close();
    myResponseStream.Close();

    return retString;
    }
    1. 按钮的调用代码
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      string url = "http://localhost:3003/";
      string param= "{\"infile\":\"{ xAxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']},series: [{ data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]}]}; \",\"callback\":\"function(chart) { chart.renderer.arc(200, 150, 100, 50, -Math.PI, 0).attr({ fill: '#FCFFC5',stroke: 'black','stroke-width' : 1}).add(); } \",\"constr\":\"Chart\"}";
      TextBox1.Text= HttpPostNew(url, param);
      MemoryStream stream = new MemoryStream(Convert.FromBase64String(TextBox1.Text));
      Bitmap bmp = new Bitmap(stream);
      string randomName = System.DateTime.Now.ToString("yyyyMMddhhssmm") + ".png";
      string saveUrl = Server.MapPath("/images/")+randomName;
      bmp.Save(saveUrl, ImageFormat.Png);
      stream.Dispose();
      stream.Close();
      bmp.Dispose();
      Image1.ImageUrl = "~/images/"+ randomName;

三. 效果展示啦

最后将base64转换成图片


DEMO 下载地址 点我下载

你想要的生活都会还给你

你正在为自己的未来打拼,也许有时候会感觉看不到尽头。但你要相信,度过这一段努力得自己都能感动自己的日子之后,你想要的岁月统统都会还给你!

随手拍

一个旅行者,在一条大河旁看到了一个婆婆,正在为渡水而发愁。已经精疲力竭的他,用尽浑身的气力,帮婆婆渡过了河,结果,过河之后,婆婆什么也没说,就匆匆走了。

旅行者很懊悔。他觉得,似乎很不值得耗尽气力去帮助婆婆,因为他连“谢谢”两个字都没有得到。

哪知道,几小时后,就在他累得寸步难行的时候,一个年轻人追上了他。年轻人说,谢谢你帮了我的祖母,祖母嘱咐我带些东西来,说你用得着。说完,年轻人拿出了干粮,并把胯下的马也送给了他。

不必急着要生活给予你所有的答案,有时候,你要拿出耐心等等。即便你向空谷喊话,也要等一会儿,才会听见那绵长的回音。也就是说,生活总会给你答案,但不会马上把一切都告诉你。

其实,岁月是一棵纵横交错的巨树。而生命,是其中飞进飞出的小鸟。如果哪一天,你遭遇了人生的冷风冻雨,你的心已经不堪承受,那么,也请你等一等,要知道,这棵巨树正在生活的背风处为你营造出一种春天的气象,并一点一点靠近你,只要你努力了。

回报不一定在付出后立即出现。只要你肯等一等,生活的美好,总在你不经意的时候,盛装莅临。

使用 Swiftype 创建一个随心所欲的搜索引擎

Swiftype 是个什么东东?

Swiftype 可以为网站及移动 app 提供内置搜索引掣服务。其部署十分简单,只须输入 URL 地址平台即可执行对用户网站的抓取,插入 JavaScript 代码嵌入网站就即完成搜索引擎的创建。Swiftype 还提供了分析服务,供网站检索分析用户的搜索行为和使用偏好。Swiftype 还支持对搜索结果排序进行定制。

Swiftype 有什么优点?

  • 无须你在后端写任何代码,仅仅创建一个引用,引入脚本即可在网站展现一个搜索界面
  • 抓取的内容全,当输入URL时,无论你是静态的还是动态的网页,都将把每个URL抓回去,若有些链接没抓到,也可以通过手动提交地址
  • 灵活定制,例如搜索框的定制,搜索结果页的定制,展示的字段也可以定制,抓取规则的过滤定制
  • 接口丰富,可通过很多种方式去请求搜索api,然后获取搜索后返回的数据
  • 安全机制校验,不用担心数据会被其他人盗用
  • 支持跨域请求,支持搜索关键词统计等等
  • 支持智能提示,自定义排序等

查看更多

gojs 学习笔记(1)

gojs 入门讲解 ——-作者 Peng8

gojs 是一款非常强大的绘图工具,可以用来画流程图、树图、关系图、力导图、甘特图、电流图等等一些很复杂炫酷的图形。以下是我学习的笔记,帮助大家理解,如有不对的地方请谅解

下载

官方网站下载gojs相关的资源包,里面包含了例子、API等资源文件 传送门

一个简单的流程图

1
var $ = go.GraphObject.make;

注释:按照我自己的理解,这个全局变量相当于一个画笔,即定义一个画笔工具。之后我们就可以通过$符号来调用它自身的一些方法、属性、枚举对象等。
有了画笔,那我们还需要画布,于是我们需要定义一个画布用来装载一些具体内容

1
2
3
4
5
6
7
8
var myDiagram =$(go.Diagram, "myDiagram",{
initialAutoScale: go.Diagram.Uniform,
contentAlignment: go.Spot.Center,
layout:$(go.ForceDirectedLayout,{
defaultSpringLength: 30,
defaultElectricalCharge: 100
})
});

注释:go.Diagram 就是我们要定义的画布,注意了,第二个参数 “myDiagram” ,这里是要渲染的DIV 的Id 名称,contentAlignment是内容的对齐方式,layout 代表画布里的元素布局方式,采用了力导图自然排列。
这个画笔可以绘制节点、链接、区域、图案、形状、文本等,例如我们要写一个文本就可以这样写:

1
2
3
4
5
6
$(go.TextBlock,{
text:"www.peng8.net",
stroke: "red",
font: "bold 10pt helvetica, bold arial, sans-serif",
margin: 4
})

注释:上面这段代码应该很好理解,用画笔绘制了一个文本对象go.TextBlock ,并为它填充了属性 text、stroke、font、margin 等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
myDiagram.nodeTemplate = $(go.Node, "Auto",
$(go.Shape, "RoundedRectangle",
{
fill: "white",
stroke: "red"
},
new go.Binding("fill", "color")
),
$(go.TextBlock,
{
font: "bold 10pt helvetica, bold arial, sans-serif",
margin: 4
},
new go.Binding("text", "text"))
);

注释:上面这段代码定义了一个节点模版,一个流程图,由很多很多个节点构成,在节点模版里面有定义了2个模型,一个是形状一个是文本,首先通过go.Shape 定义了一个 圆角矩形 ,默认填充色为 白色,边框颜色为 红色。
注意了,仔细看我们会发现 TextBlock 里相对与上面那个TextBlock ,少了一个text属性节点,而在最下面多了一行 new go.Binding("text","text") ,这什么意思呢?这是申明动态绑定text属性,将数据源中提供text字段的值赋值给当前的text属性,随后介绍数据源的格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
myDiagram.linkTemplate =
$(go.Link,
{ adjusting: go.Link.Stretch, reshapable: true },
new go.Binding("points").makeTwoWay(),

//new go.Binding("curviness", "curviness"),
$(go.Shape,
{
isPanelMain: true,
stroke: "black"
}),
$(go.Shape,
{
toArrow: "standard",
stroke: null
}),


$(go.TextBlock,
{
textAlign: "center",
segmentOffset: new go.Point(0, -10),
font: "10pt helvetica, arial, sans-serif",
stroke: "#555555",
margin: 4
},
new go.Binding("text", "text")
)
);

注释:我们定义了节点模版,构成了流程图的每一个点,所谓流程图自然有流向,于是有了连接点与点的线,这里我们称之 流程线 ,可以是虚线、实线、带箭头、不带箭头等。同样上面通过go.Link 构建了流程线,这个对象里面包含了 2个形状,一个文本,2个形状一个用来画线,一个用来画箭头,文本用来显示线上的label。至于里面的属性我就不做详细介绍了,大家可以看API。

最后就是如何给流程图填充动态数据了,这里我采用了json的方式,流程图赋值就是一句话就够了

1
myDiagram.model = go.Model.fromJson(jsonList);

jsonList 是我前端定义用来接收ajax返回数据的一个对象,它的数据结构是

1
2
3
4
5
var jsonList = {
nodeKeyProperty: "key",
nodeDataArray: [{key:1,text:"节点a"},{key:2,text:"节点b"},{key:3,text:"节点c"}],
linkDataArray: [{from:1,to:2,text:"我是节点a指向节点b"},{from:2,to:3,text:"我是节点b指向节点c"},{from:3,to:1,text:"我是节点c指向节点a"}]
};

注释:jsonList 的结构是固定的,包含了nodeKeyPropertynodeDataArraylinkDataArray 三个属性,分别代表了 关联的主键节点数据节点对应关系数据 ,上面from 和to 即 开始节点的主键指向结束节点的主键。
我们把上面所有代码合起来,就形成了一个简单的流程图,上图上真相

简单的流程图

gojs简单流程图先介绍到这里,后续还会有自定义节点图标、节点编辑、节点扩充等等相关的介绍

敬请期待,待续中…..