Giter Site home page Giter Site logo

Unwanted circle on link path about d3-sankey HOT 1 OPEN

Spenhouet avatar Spenhouet commented on July 19, 2024
Unwanted circle on link path

from d3-sankey.

Comments (1)

Spenhouet avatar Spenhouet commented on July 19, 2024

It turned out that this is in fact an issue with the current implementation which uses the stroke width to draw the links - which breaks down if the link is shorter than wide.
You can find more details on this issue here: https://observablehq.com/@enjalot/weird-sankey-links

The solution is to actually draw the outline of the link.
image

You can find my full solution here: https://stackoverflow.com/a/72593081/2230045

Feel free to use and adapt this code:

/** @type {Function} [linkWidth=d => '0.9'] - A function to return a float to scale the link width. */
export let linkWidth = (d) => 0.9;

/**
 * This function is a drop in replacement for d3.sankeyLinkHorizontal().
 * Except any accessors/options.
 * @param {Object} link - Link object.
 * @param {Number} link.y0 - y coordinate for the start of the link.
 * @param {Number} link.y1 - y coordinate for the end of the link.
 * @param {Number} link.width - Width of the link.
 * @param {Object} link.source - Source node object.
 * @param {Number} link.source.x1 - x coordinate for the start of the link.
 * @param {Object} link.target - Target node object.
 * @param {Number} link.target.x0 - x coordinate for the end of the link.
 **/
function sankeyLinkPathHorizontal(link) {
    // Start and end of the link
    let sx1 = link.source.x1;
    let tx0 = link.target.x0 + 1;

    // All four outer corners of the link
    // where e.g. lsy0 is the upper corner of the link on the source side
    let lsy0 = link.y0 - (link.width / 2) * linkWidth(link);
    let lsy1 = link.y0 + (link.width / 2) * linkWidth(link);
    let lty0 = link.y1 - (link.width / 2) * linkWidth(link);
    let lty1 = link.y1 + (link.width / 2) * linkWidth(link);

    // Center (x) of the link
    let lcx = sx1 + (tx0 - sx1) / 2;

    // Define outline of link as path
    let path = d3.path();
    path.moveTo(sx1, lsy0);
    path.bezierCurveTo(lcx, lsy0, lcx, lty0, tx0, lty0);
    path.lineTo(tx0, lty1);
    path.bezierCurveTo(lcx, lty1, lcx, lsy1, sx1, lsy1);
    path.lineTo(sx1, lsy0);
    return path.toString();
}

/**
 * This function is a drop in replacement for d3.sankeyLinkVertical().
 * Except any accessors/options.
 * @param {Object} link - Link object.
 * @param {Number} link.y0 - y coordinate for the start of the link.
 * @param {Number} link.y1 - y coordinate for the end of the link.
 * @param {Number} link.width - Width of the link.
 * @param {Object} link.source - Source node object.
 * @param {Number} link.source.x1 - x coordinate for the start of the link.
 * @param {Object} link.target - Target node object.
 * @param {Number} link.target.x0 - x coordinate for the end of the link.
 **/
function sankeyLinkPathVertical(link) {
	// Start and end of the link
	let sy1 = link.source.x1;
	let ty0 = link.target.x0 + 1;

	// All four outer corners of the link
	// where e.g. lsx0 is the right corner of the link on the source side
	let lsx0 = link.y0 - (link.width / 2) * linkWidth(link);
	let lsx1 = link.y0 + (link.width / 2) * linkWidth(link);
	let ltx0 = link.y1 - (link.width / 2) * linkWidth(link);
	let ltx1 = link.y1 + (link.width / 2) * linkWidth(link);

	// Center (y) of the link
	let lcy = sy1 + (ty0 - sy1) / 2;

	// Define outline of link as path
	let path = d3.path();
	path.moveTo(lsx0, sy1);
	path.bezierCurveTo(lsx0, lcy, ltx0, lcy, ltx0, ty0);
	path.lineTo(ltx1, ty0);
	path.bezierCurveTo(ltx1, lcy, lsx1, lcy, lsx1, sy1);
	path.lineTo(lsx0, sy1);
	return path.toString();
}

from d3-sankey.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.