记录一次曲折的需求完成

12 篇文章 0 订阅
2 篇文章 0 订阅

需求:

将WPF程序中一段调用Cgal编译的dll的treemap算法 改成 调用d3.js中的packing Circle算法

重要程度

⭐⭐⭐⭐

人物性格:

非常懒

时限

10小时

思路

一.将d3.js打包成dll,然后WPF调用(因为C#中有现成的调用dll代码,因此修改的非常少)

a) 尝试JScript.NET

在VS开发人员命令行中输入

 jsc /t:library d3.js

报错

D://1.js(2,323) : error JS1160: 特性列表不适用于当前上下文
D://1.js(2,334) : error JS1193: 应为“,”或“)”
D://1.js(2,449) : error JS1018: “return”语句在函数范围外
D://1.js(2,479) : error JS1195: 应为表达式
D://1.js(2,513) : error JS1195: 应为表达式
D://1.js(2,527) : error JS1004: 应为“;”
D://1.js(2,543) : error JS1004: 应为“;”
D://1.js(2,552) : error JS1010: 应为标识符
D://1.js(2,661) : error JS1195: 应为表达式
D://1.js(2,676) : error JS1010: 应为标识符
D://1.js(2,677) : warning JS1111: 已经定义了“t”
D://1.js(2,780) : error JS1002: 语法错误
D://1.js(2,825) : error JS1111: 已经定义了“i”
D://1.js(2,881) : error JS1160: 特性列表不适用于当前上下文
D://1.js(2,911) : error JS1004: 应为“;”
D://1.js(2,913) : error JS1004: 应为“;”
D://1.js(2,916) : error JS1006: 应为“)”
D://1.js(2,917) : error JS1004: 应为“;”
D://1.js(2,947) : error JS1160: 特性列表不适用于当前上下文
D://1.js(2,964) : error JS1004: 应为“;”
D://1.js(2,966) : error JS1004: 应为“;”
D://1.js(2,969) : error JS1006: 应为“)”
D://1.js(2,970) : error JS1004: 应为“;”
D://1.js(2,978) : error JS1197: 错误太多。该文件可能不是 JScript 文件

放弃

二.WPF直接调用js代码

a) 尝试MSScriptControl.ScriptControl

//string _MD5_js = "MD5.js";
        private object ExecuteScript(string funcName, string argument, string jsPath)
        {
            string js = System.IO.File.ReadAllText(jsPath);
            object o = ExecuteScript(string.Format("{0}('{1}')", funcName, argument), js);
            return o;
        }

        /// <summary>
        /// 执行JS
        /// </summary>
        /// <param name="sExpression">参数体</param>
        /// <param name="sCode">JavaScript代码的字符串</param>
        /// <returns></returns>
        private object ExecuteScript(string sExpression, string sCode)
        {
            MSScriptControl.ScriptControl scriptControl = new MSScriptControl.ScriptControl();
            scriptControl.UseSafeSubset = true;
            scriptControl.Language = "JScript";
            scriptControl.AddCode(sCode);
            try
            {
                return scriptControl.Eval(sExpression);
            }
            catch (Exception ex)
            {
         
            }
            return null;
        }

报错
在这里插入图片描述
放弃

三.Asp.net后台调用js代码,然后WPF通过post获取数据(因为Asp.net有现成的post函数)

a) 尝试ValuesController.cs中在Post函数中调用JS代码

在这里插入图片描述
对MVC不是特别熟,没有余力去思考ValuesController对应的view在哪儿了
放弃

四.直接写一个post服务器,然后WPF通过post获取数据

服务器

// postserver.js
// 获取客户端post来的title、text参数,然后返回给客户端

var http = require('http');
var querystring = require('querystring');

var server = http.createServer(function(req, res) {
    var post = '';

    req.on('data', function(chunk) {
    post += chunk;
    });

    req.on('end', function() {
    post = querystring.parse(post);

    res.write(post.title);
    res.write(post.text);
    res.end();
    });
}).listen(3000);

在控制台中执行node server.js,开启http服务,监听3000端口。

客户端

var http = require('http');
var querystring = require('querystring');

var contents = querystring.stringify({
    title: 'Hello ',
    text: 'Arthur',
});

var options = {
    host: '127.0.0.1',
    port: '3000',  //非80端口需要指定,如果是80端口则可以省略。
    path: '/',
    headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': contents.length
    }
};

var req = http.request(options, function(res) {
    res.setEncoding('utf8');
    res.on('data', function(data) {
    console.log('request begin:');
    console.log(data);
    console.log('request end.');
    console.log('--------------------');
    });
});

req.write(contents);
req.end();

在另一个控制台中执行node client.js

a) 安装Nodejs

b) 写一个简单的post服务器和客户端测试

在这里插入图片描述
成功

c) 在post服务器中调用d3.js

var d3 = require("./d3.js");

报错

ReferenceError: XMLHttpRequest is not defined
    at nu (C:\Users\lunhui\Desktop\d3.js:2:63462)
    at Object.json (C:\Users\lunhui\Desktop\d3.js:2:65084)
    at d33 (C:\Users\lunhui\Desktop\test.js:41:8)
    at IncomingMessage.<anonymous> (C:\Users\lunhui\Desktop\test.js:21:18)
[90m    at IncomingMessage.emit (node:events:406:35)[39m
[90m    at endReadableNT (node:internal/streams/readable:1329:12)[39m
[90m    at processTicksAndRejections (node:internal/process/task_queues:83:21)[39m
α)尝试1:

原因:xmlhttprequest 不是Node 内置的,需要单独安装:
安装命令:npm install xmlhttprequest

失败

β)尝试2:

搜索nodejs调用d3.js
报错
在这里插入图片描述
安装express

npm install express

然后不报错了,但是脚本也没用
失败

γ)尝试3:

找到一份代码node.js中用d3.js

npm install d3

报错
在这里插入图片描述
尝试解决方案1
Check for 2 things:

Node version >= 14. It only works with latest version of node.
Make sure your package.json includes a line for “type”: “module”, Without this line node assumes you want to use Common JS modules rather than ESM.

报错
在这里插入图片描述
尝试解决方案2
在你要require的代码前引入如下代码即可:

import { createRequire } from 'module';
const require = createRequire(import.meta.url);

报错
在这里插入图片描述
尝试解决方案3
在 Node.js 中使用 import
Node 版本需在 9.0 及以上
不加 loader 时候,使用 import/export 的文件后缀名必须为 .mjs

import d3 from 'd3'

在这里插入图片描述
修改为

import * as d3 from 'd3';

其他的require也都要改成这个亚子
成功!

d) 尝试连接
报错

ReferenceError: fetch is not defined

在node_module/d3_fectch/src/json.js开头添加以下两句

import { fetch as fetchPolyfill } from 'whatwg-fetch'
global.fetch = fetchPolyfill

报错
在这里插入图片描述
把var转换成字符串

报错
在这里插入图片描述
node_modules\whatwg-fetch\dist\fetch.umd.js
添加

 import * as XMLHttpRequest from 'xmlhttprequest';

报错
在这里插入图片描述
这是个终极大错!
退无可退!
放弃不了了!
现在已经22点.明天记续

给明天留个希望: d3.json()和d3.csv()出了问题,也就是读取文件出了问题

五.中期总结

我好像没有时间详细记录问题和解决方案了,只能草草描述.

果然是读取文件出了问题
换成了fs.readFileSync就再也没有报错了
然而接下来的第二天时间却浪费在了d3.js的返回数据格式上

这件事给我的教训是 一定要先去看说明文档,不要自己想当然的测试
https://observablehq.com/@d3/d3-hierarchy1

第三天的时间浪费在了fs.readFileSync之后没有转化成Json格式.

var root = JSON.parse(fs.readFileSync('./flare-2.json', 'utf8'));

成功输出正确格式的root;
终于,马上要成功了.

然而好像并没有那个简单,除了根节点的x,y被计算出来,其他的所有属性都没有记录.

六.神奇的转折-C#

结果在github找到一个C#的circle packing程序
Circle Packing Algorithm for C# (in a Windows Universal project)
兜兜转转又回到最初的起点

正在下载相关组件,测试是否work
发现Visual Studio 2017 和Visual Studio 2019 都打不开UWP项目
期间测试了一波下载Visual Studio 2015
失败

Visual Studio 2019 加载UWP项目
失败

于是直接从源代码里摘出来放到WPF项目中,然而,发现并不是自己需要的效果
失败
在这里插入图片描述

七.重回Html

又回到Github,找到了Html
Github:balakrishna-k/CirclePack
这个能运行
在这里插入图片描述
并且可以获取到数据的返回值,很是成功.

var circle = g.selectAll("circle")
    .data(nodes)
    .enter().append("circle")
      .attr("class", function(d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; })
      ;

alert(circle._groups[0][0].__data__.x);

八.Html的Socket通信

html的websocket与我已有的C#的TCP socket连接失败
Websocket错误:ERR_INVALID_HTTP_RESPONSE
原因是:
在这里插入图片描述
因此实现了一个C#的WebSocket的服务器,连接成功.

最终我的伞兵架构为下图:
在这里插入图片描述
1.把服务端放在服务器而不是本地上是因为快速解决跨域问题(后来放弃了,因为外网IP的问题,最后放在了本地IIS服务器上)
2.写两个socket是因为WPF和服务端的Tcp socket是现成的,最简单的修改是直接websocket与tcp socket之间互传字符串

九.最终调试

在这里插入图片描述
经过了几个小bug,最终三个程序联调成功.(C#服务器调用UI组件一定要用Dispatcher.BeginInvoke,否则会出各种奇怪的bug)

剩下的就是规范数据传输格式,封装函数等工作了.

十.总结

看似初衷是为了省事,实则花费了更多时间和精力.
究竟是变通了,不撞南墙了?还是浮躁了,静不下来了呢?

十一.番外

如同之前很多次一样,在一切都结束的时候,我才突然意识到,d3.js中的packing Circle算法不能计算非矩形内的packing circle.
因此,这些工作好像都没有用上.
之前是想得太多,做的太少.现在是想的太少,直接去莽.
都是教训

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值