From 9e79117c6174722b5ade7efbda8a1e3f4166b469 Mon Sep 17 00:00:00 2001 From: Sam Rich Date: Fri, 28 Feb 2020 09:48:42 -0500 Subject: [PATCH] [PRTL-2967] Lolliplot X-axis position (#58) --- .../@oncojs/react-lolliplot/LolliplotNode.js | 67 +++++++++++++------ .../@oncojs/react-lolliplot/utils/uuid.js | 1 - package.json | 1 + yarn.lock | 5 ++ 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/modules/node_modules/@oncojs/react-lolliplot/LolliplotNode.js b/modules/node_modules/@oncojs/react-lolliplot/LolliplotNode.js index b6ff53a..17ada2b 100644 --- a/modules/node_modules/@oncojs/react-lolliplot/LolliplotNode.js +++ b/modules/node_modules/@oncojs/react-lolliplot/LolliplotNode.js @@ -3,6 +3,7 @@ import invariant from 'invariant' import ReactFauxDOM from 'react-faux-dom' import range from 'lodash.range' +import uniq from 'lodash.uniq' import attrs from './utils/attrs' import { dim } from './utils/spatial' import uuid from './utils/uuid' @@ -33,24 +34,42 @@ let Lolliplot = ({ } = {}) => { invariant(d3, `You must pass in the d3 library, either v3 || v4`) + const xTickInt = (max - min) / numXTicks + + const uniqueXTicks = uniq( + range(numXTicks - 1) + .map(x => x + 1) + .map(i => Math.round(xTickInt * i + min)) + ) + + const numUniqueXTicks = uniqueXTicks.length + + const xTickDistance = numUniqueXTicks.length === 1 + ? 1 + : uniqueXTicks[1] - uniqueXTicks[0] + + // min & max are invisible ticks on the far left and right + min = uniqueXTicks[0] - xTickDistance + max = uniqueXTicks[numUniqueXTicks - 1] + d3.selection.prototype.attrs = attrs d3.scaleOrdinal = d3.scaleOrdinal || d3.scale.ordinal d3.scaleLinear = d3.scaleLinear || d3.scale.linear - let root = ReactFauxDOM.createElement(`div`) + const root = ReactFauxDOM.createElement(`div`) invariant(root, `Must provide an element or selector!`) width = width || root.clientWidth height = height || root.clientHeight - let uniqueSelector = uuid() - let xAxisLength = width - yAxisOffset - let scale = xAxisLength / domainWidth + const uniqueSelector = uuid() + const xAxisLength = width - yAxisOffset + const scale = xAxisLength / domainWidth - let visibleData = data.filter(d => d.x > min && d.x < max) + const visibleData = data.filter(d => d.x >= min && d.x <= max) - let scaleLinear = d3 + const scaleLinear = d3 .scaleLinear() .domain([min, max]) .range([yAxisOffset, width]) @@ -59,7 +78,7 @@ let Lolliplot = ({ let highestValue = Math.max(10, maxY) - let scaleLinearY = d3 + const scaleLinearY = d3 .scaleLinear() .domain([-highestValue / numXTicks, highestValue]) .range([height - xAxisOffset, 15]) @@ -139,9 +158,15 @@ let Lolliplot = ({ .attrs({ class: d => `mutation-line-${d.id}`, 'clip-path': `url(#${uniqueSelector}-chart-clip)`, - x1: d => scaleLinear(d.x), + x1: d => { + let x1 = scaleLinear(d.x) + return x1 + }, y1: height - xAxisOffset, - x2: d => scaleLinear(d.x), + x2: d => { + let x2 = scaleLinear(d.x) + return x2 + }, y2: d => scaleLinearY(d.y), stroke: `rgba(0, 0, 0, 0.2)`, }) @@ -268,37 +293,41 @@ let Lolliplot = ({ svg.append(`g`).attr(`class`, `xTicks`) - let length = (max - min) / numXTicks - let olength = domainWidth / numXTicks + let olength = domainWidth / numUniqueXTicks + + let tickXPositions = {} d3Root .select(`.xTicks`) .append(`g`) .selectAll(`text`) - .data(range(numXTicks - 1).map(x => x + 1)) + .data(range(numUniqueXTicks - 1).map(x => x + 1)) .enter() .append(`text`) - .text(i => Math.round(length * i + min)) + .text(i => uniqueXTicks[i - 1]) .attrs({ class: i => `xTick-text-${i}`, - x: i => olength * i * scale + yAxisOffset, + x: i => { + let tickX = olength * i * scale + yAxisOffset + tickXPositions[uniqueXTicks[i - 1]] = tickX + return tickX + }, y: height - xAxisOffset + 20, 'font-size': `11px`, 'text-anchor': `middle`, 'pointer-events': `none`, }) - for (let i = 1; i < numXTicks; i++) { - let length = domainWidth / numXTicks - + for (let i = 1; i < numUniqueXTicks; i++) { + const x = olength * i * scale + yAxisOffset d3Root .select(`.xTicks`) .append(`line`) .attrs({ class: `xTick-line-${i}`, - x1: length * i * scale + yAxisOffset, + x1: x, y1: height - xAxisOffset, - x2: length * i * scale + yAxisOffset, + x2: x, y2: height - xAxisOffset + 10, stroke: theme.black, 'pointer-events': `none`, diff --git a/modules/node_modules/@oncojs/react-lolliplot/utils/uuid.js b/modules/node_modules/@oncojs/react-lolliplot/utils/uuid.js index 26d8f4c..6548018 100644 --- a/modules/node_modules/@oncojs/react-lolliplot/utils/uuid.js +++ b/modules/node_modules/@oncojs/react-lolliplot/utils/uuid.js @@ -1,5 +1,4 @@ let uuid = a => a ? (a ^ Math.random() * 16 >> a / 4).toString(16) : ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid) - export default uuid diff --git a/package.json b/package.json index e2f4967..c71ee3a 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "lodash.countby": "^4.6.0", "lodash.range": "^3.2.0", "lodash.startcase": "^4.4.0", + "lodash.uniq": "4.5.0", "react": "^15.4.1", "react-faux-dom": "^3.0.1", "redux": "^3.6.0", diff --git a/yarn.lock b/yarn.lock index d6f40dc..115801b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3772,6 +3772,11 @@ lodash.toplainobject@^3.0.0: lodash._basecopy "^3.0.0" lodash.keysin "^3.0.0" +lodash.uniq@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + lodash.words@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.words/-/lodash.words-3.2.0.tgz#4e2a8649bc08745b17c695b1a3ce8fee596623b3"