JesseLuo

JesseLuo 查看完整档案

厦门编辑  |  填写毕业院校  |  填写所在公司/组织 luosijie.github.io/ 编辑
编辑

UI设计师
前端爱好者

个人动态

JesseLuo 赞了回答 · 4月28日

正则替换括号内的指定字符

d(?=[^()]*\)) 替换为 #

关注 1 回答 1

JesseLuo 提出了问题 · 4月28日

正则替换括号内的指定字符

比如有字符串
"asdad(dadaf)addf"

想替换 括号里面的 d

结果为
"asdad(#a#af)addf"

正则要怎么写呢

关注 1 回答 1

JesseLuo 赞了文章 · 3月2日

d3-force 力导图 源码解读与原理分析【一】

首先先推荐一下某呆翻译的d3-force的中文文档:https://github.com/xswei/D3-V...
在我们解读源码前还请读者先熟悉一下force相关的API,以及es6语法 .

如有分析不当之处还请留言指出,谢谢~

那我们进入正题吧

D3-force 有什么

我们来看一下index.js 这个文件大家可以理解为force的对外统一出口。当然你也可以自定义使用这些模块。

// index.js
export {default as forceCenter} from "./src/center"; // 设置力导图点阵中心
export {default as forceCollide} from "./src/collide"; // 碰撞
export {default as forceLink} from "./src/link";
export {default as forceManyBody} from "./src/manyBody";
export {default as forceSimulation} from "./src/simulation";
export {default as forceX} from "./src/x";
export {default as forceY} from "./src/y";

其他引用模块

//collide.js
import constant from "./constant";    // 构造常量函数
import jiggle from "./jiggle";        // 微小晃动随机数
import {quadtree} from "d3-quadtree"; // 四叉树

模块1:center.js 设置力导图点阵中心

此处代码使用的是单例对象模式,读者要注意,切勿与类对象理解混了。

export default function(x, y) {
  var nodes; // 使用闭包构建私有变量,存储nodes。

  if (x == null) x = 0; // 力导图中心位置 x 默认值为0
  if (y == null) y = 0; // 力导图中心位置 y 默认值为0
   
  // force 单例对象
  function force() {
    var i,
        n = nodes.length,
        node,   // 临时变量用于循环
        sx = 0, // 临时变量用于计算
        sy = 0; // 临时变量用于计算
    
    for (i = 0; i < n; ++i) {
      // sx = sum(node.x);  节点x之和
      // sy = sum(node.y);  节点y之和
      node = nodes[i], sx += node.x, sy += node.y;
    }

    for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
      // sx / n 是点阵的中心x坐标;sy / n 是点阵的中心y坐标。
      // node.x = node.x + (x - (sx / n)); 该计算与此表达式等价,这样读者应该更好理解;
      // 坐标加减即平移坐标,即将整个点阵中心平移到坐标(x,y)
      node = nodes[i], node.x -= sx, node.y -= sy;
    }
  }
  // 初始化,为nodes私有变量赋值
  force.initialize = function(_) {
    nodes = _;
  };
  // 如果传入参数x则设置x,否则返回当前力导图中心位置 x
  force.x = function(_) {
    return arguments.length ? (x = +_, force) : x; 
  };
  // 如果传入参数y则设置y,否则返回当前力导图中心位置 y
  force.y = function(_) {
    return arguments.length ? (y = +_, force) : y;  
  };

  return force; // 返回 force对象
}

模块2:constant.js 创建一个常量函数

// 构造一个返回参数值的常量函数
// let a = constant(123); a() 输出: 123
export default function(x) {
  return function() {
    return x;
  };
}

模块3:jiggle.js 微小晃动随机数

// jiggle.js
// 微小晃动随机数
export default function() {
  return (Math.random() - 0.5) * 1e-6; // 1e-6 ==> 1*10的-6次方
}

模块4:collide.js 碰撞

import constant from "./constant";    // 构造常量函数
import jiggle from "./jiggle";        // 微小晃动随机数
import {quadtree} from "d3-quadtree"; // 四叉树

// vx vy 是指当前节点的运动速度
function x(d) {
  return d.x + d.vx; // 运动一步 x + vx 
}

function y(d) {
  return d.y + d.vy; // 运动一步 y + vy
}

export default function(radius) {
  var nodes,
      radii,
      strength = 1, // 力度
      iterations = 1;
      
  // radius 设置默认值,值类型为常量函数;
  if (typeof radius !== "function") radius = constant(radius == null ? 1 : +radius);

  // 单例对象模式
  function force() {
    var i, n = nodes.length,
        tree,
        node,
        xi,
        yi,
        ri,  // 半径
        ri2; // 半径平方
// -------------- 四叉树相关,**后文有详细分析**----------
    for (var k = 0; k < iterations; ++k) {
      // 以x,y访问器构建一个四叉树,即节点运动到下一步位置为坐标(就像我们走夜路,探出一步试试看)
      // visitAfter是后序遍历树的节点,执行prepare为每个节点求半径r,参数为各个节点,
      // 返回树的跟节点root。
      tree = quadtree(nodes, x, y).visitAfter(prepare); 
      // for循环普通遍历节点
      for (i = 0; i < n; ++i) {
        node = nodes[i];
        ri = radii[node.index], ri2 = ri * ri; // r平方(勾股定理用)
        xi = node.x + node.vx;// 运动一步 x + vx 
        yi = node.y + node.vy;// 运动一步 y + vy 
        // 前序遍历所有节点,apply返回true则不访问其子节点
        tree.visit(apply); 
      }
    }

    function apply(quad, x0, y0, x1, y1) {
      var data = quad.data, rj = quad.r, r = ri + rj;// 两个点与其作用域构成两个圆,请参考之前的文章,圆与圆的碰撞测验。
      if (data) { // 存在data即叶子节点,每个叶子节点为一个坐标点
        if (data.index > node.index) {
          // 因为这是二重循环,所有index小于自身的点坐标已经与自身判断过了,此处是为了避免重复测验
          // 设第一重循环Node[i]为节点A(xi,yi) 第二重循环为节点B(data.x,data.y)下一步运动(+=vx,+=vy)
          var x = xi - data.x - data.vx, // Ax - Bx
              y = yi - data.y - data.vy, // Ay - By
              l = x * x + y * y;  // 勾股定理 d^2 = x^2 +y^2
          if (l < r * r) { // 判断是否碰撞,如果碰撞执行以下,l:实际距离平方,r:半径之和
            if (x === 0) x = jiggle(), l += x * x; // 避免x值为0
            if (y === 0) y = jiggle(), l += y * y; // 避免y值为0
            // strength:碰撞力的强度,可以理解为两点之间的斥力系数
            // 见后文碰撞测验的图
            // l = 重叠长度/实际距离 * 碰撞力度
            // 重叠约多,斥力越大。斥力影响点的运动速度
            l = (r - (l = Math.sqrt(l))) / l * strength; 
            // 根据求出的斥力计算AB点新的运动速度与方向
            // A点x方向的运动速度 
            // A速度 += B速度 -= 使得AB两点往相反方向运动。注意,这里的x是B到A的距离,所有是A+= ,B-=
            // 但斥力的原因会使得节点的vx ,vy 趋近于0.
            // node.vx = B-A点x方向距离 *= 斥力 * B半径平方(rj = B半径平方)/( A半径平方+B半径平方);r = B半径平方/( A半径平方+B半径平方)
            node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
            // 同x方向
            node.vy += (y *= l) * r;
            data.vx -= x * (r = 1 - r);
            data.vy -= y * r;
          }
        }
        return;
      }
      // 如果是父节点,这里需要读者理解四叉树【后面一篇文章会讲解】
      // 节点坐标为中心的正方形,如果没有覆盖到该父节点的正方形区域,这改点与此父节点的任何子节点都不会发生碰撞,则无需遍历其子节点校验。
      // 返回true 不遍历子节点
      // 这也是v4 相比v3对性能优化最重要的一个步骤,成倍的减少计算量
      return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
    }
  }
  // 遍历树节点过滤器,返回true节点不可见
  function prepare(quad) {
    // quad.data是叶子节点才有的,所以这里是判断是否是叶子节点
    if (quad.data) return quad.r = radii[quad.data.index];
    for (var i = quad.r = 0; i < 4; ++i) {
      // 因为是后序遍历,所以节点的叶子节点一定在之前已经遍历过。
      // 取叶子节点四个象限最大的r
      if (quad[i] && quad[i].r > quad.r) {
        quad.r = quad[i].r;
      }
    }
  }
//---------------------------------------------------------------------------------------
  function initialize() {
    if (!nodes) return; // 判断是否有节点
    var i, n = nodes.length, node;
    radii = new Array(n);
    // 按照node.index索引排序nodes 并又 radius【后文解析】 计算出半径 后 存储在 radii 
    for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
  }

  force.initialize = function(_) {
    nodes = _; // 赋值节点
    initialize(); // 初始化
  };

  force.iterations = function(_) {
    // get or set iterations (迭代次数)
    return arguments.length ? (iterations = +_, force) : iterations;
  };
  
  force.strength = function(_) {
    // get or set strength(力度)
    return arguments.length ? (strength = +_, force) : strength;
  };

  force.radius = function(_) {
    // 前端加+号 将字符串转为number  +"123" === 123
    // 有参数:
    // 执行1:(radius = typeof _ === "function" ? _ : constant(+_)
     //radius 值是一个返回自身的函数
    // 执行2:initialize()
    // 执行3:return force
    // 无参数:
    // 执行:return radius
    return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), initialize(), force) : radius;
  };

  return force;
}

clipboard.png
碰撞测验

查看原文

赞 3 收藏 2 评论 0

JesseLuo 分享了头条 · 2月2日

基于threejs绘制geojson地图

赞 0 收藏 0 评论 0

JesseLuo 提出了问题 · 2019-09-01

公众号开发-canvas转成图片下载到手机

将 canvas 下载到手机
公众号开发怎么做呢

关注 1 回答 0

JesseLuo 提出了问题 · 2019-08-30

mapbox-gl 如果给3D模型添加 不同颜色的边框

比如下面的 模型都挤在一起了
如何给加上边框颜色来区分
clipboard.png

关注 1 回答 0

JesseLuo 提出了问题 · 2019-05-16

xlsx插件解析Excel文件 样式怎么没有找到

xlsx 前端解析 Excel文件
样式找不到
要怎么处理呢

关注 1 回答 0

JesseLuo 提出了问题 · 2019-04-23

升级webpack4 和 babel 报错:vue jsx 不支持 和 命名chunk不支持

主要报2种错

1.vue jsx 不支持

clipboard.png

2.命名chunk 不支持

clipboard.png

这是我的相关配置:

.babelrc

{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins": [
        "@babel/plugin-transform-runtime",
        "@babel/plugin-syntax-dynamic-import",
        "@babel/plugin-proposal-object-rest-spread",
        "@babel/plugin-proposal-class-properties",
        "@babel/plugin-syntax-jsx",
        "transform-vue-jsx"
    ]
}

相关依赖

{
  ...
  "devDependencies": {
    "@babel/cli": "^7.4.3",
    "@babel/core": "^7.4.3",
    "@babel/helper-module-imports": "^7.0.0",
    "@babel/plugin-proposal-class-properties": "^7.4.0",
    "@babel/plugin-proposal-object-rest-spread": "^7.4.3",
    "@babel/plugin-syntax-dynamic-import": "^7.2.0",
    "@babel/plugin-syntax-jsx": "^7.2.0",
    "@babel/plugin-transform-runtime": "^7.4.3",
    "@babel/preset-env": "^7.4.3",
    "@babel/register": "^7.4.0",
    "@babel/runtime": "^7.4.3",
    "ali-oss": "4.10.0",
    "autoprefixer": "7.1.3",
    "babel-eslint": "7.2.3",
    "babel-helper-vue-jsx-merge-props": "^2.0.3",
    "babel-loader": "^8.0.5",
    "babel-plugin-dynamic-import-node": "^2.2.0",
    "babel-plugin-import": "^1.11.0",
    "babel-plugin-istanbul": "4.1.4",
    "babel-plugin-transform-vue-jsx": "^4.0.1",
    "babel-register": "6.26.0",
    "chalk": "2.1.0",
    "connect-history-api-fallback": "1.3.0",
    "copy-webpack-plugin": "4.0.1",
    "cross-env": "5.0.5",
    "css-loader": "^2.1.1",
    "eslint": "4.6.1",
    "eslint-config-airbnb-base": "12.0.0",
    "eslint-config-vue": "2.0.2",
    "eslint-friendly-formatter": "3.0.0",
    "eslint-loader": "1.9.0",
    "eslint-plugin-babel": "4.1.2",
    "eslint-plugin-import": "2.7.0",
    "eslint-plugin-jest": "21.0.0",
    "eslint-plugin-promise": "3.5.0",
    "eslint-plugin-vue": "2.1.0",
    "eventsource-polyfill": "0.9.6",
    "express": "^4.16.4",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "0.11.2",
    "friendly-errors-webpack-plugin": "1.6.1",
    "fs-promise": "2.0.3",
    "html-webpack-plugin": "^4.0.0-beta.5",
    "http-proxy-middleware": "^0.19.1",
    "js-base64": "^2.4.9",
    "json-loader": "0.5.7",
    "less": "2.7.2",
    "less-loader": "4.0.5",
    "lodash": "^4.17.11",
    "mkdir-recursive": "0.3.0",
    "mockjs": "^1.0.1-beta3",
    "opn": "5.1.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "ora": "1.3.0",
    "postcss-loader": "2.0.6",
    "promise-window": "^1.2.1",
    "rimraf": "2.6.1",
    "style-loader": "0.18.2",
    "underscore-template-loader": "0.8.0",
    "url-loader": "^1.1.2",
    "vue-loader": "^15.7.0",
    "vue-style-loader": "^4.1.2",
    "vue-template-compiler": "^2.4.2",
    "webpack": "^4.29.6",
    "webpack-bundle-analyzer": "^3.3.2",
    "webpack-cli": "^3.3.0",
    "webpack-dev-middleware": "^3.6.2",
    "webpack-dev-server": "^3.3.1",
    "webpack-hot-middleware": "^2.24.3"
  }
}

关注 5 回答 3

JesseLuo 提出了问题 · 2019-04-21

前端如何导出带公式的 Excel 文件

目前有没有比较成熟的开源方案呢:

我了解的
在线编辑方案有:
handsontable@6.2.2
导入导出方案有:
js-xlsx

怎么导出Excel带 公式 和 样式 呢

关注 2 回答 1

认证与成就

  • 获得 240 次点赞
  • 获得 137 枚徽章 获得 3 枚金徽章, 获得 39 枚银徽章, 获得 95 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2016-05-21
个人主页被 2k 人浏览