Browse Source

fix mouse move selection

merge-requests/5/head
vargburz 2 years ago
parent
commit
f480a4f69a
  1. 6
      demo.html
  2. 9
      dist/index.d.ts
  3. 47260
      dist/index.js
  4. 2
      dist/types.d.ts
  5. 8
      dist/utils.d.ts
  6. 5702
      package-lock.json
  7. 87
      src/index.ts
  8. 2
      src/types.ts
  9. 29
      src/utils.ts

6
demo.html

@ -7,7 +7,7 @@
<script src="./dist/index.js" type="text/javascript"></script>
</head>
<body>
<div id="chart" style="width: 500px; height: 500px;"></div>
<div id="chart" style="width: 50%; height: 500px;"></div>
<script type="text/javascript">
var pod = new ChartwerkBarPod(
@ -26,8 +26,8 @@
},
stacked: true,
matching: true,
// maxBarWidth: 2,
minBarWidth: 40,
maxBarWidth: 20,
minBarWidth: 4,
zoomEvents: {
scroll: { zoom: { isActive: false }, pan: { isActive: false } },
},

9
dist/index.d.ts vendored

@ -3,12 +3,17 @@ import { BarTimeSerie, BarOptions, RowValues } from './types';
import * as d3 from 'd3';
export declare class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
barYScale: null | d3.ScaleLinear<number, number>;
_seriesDataForRendring: any[];
constructor(el: HTMLElement, _series?: BarTimeSerie[], _options?: BarOptions);
protected renderMetrics(): void;
get isMatchingDisabled(): boolean;
setSeriesDataForRendering(): void;
setBarPodScales(): void;
renderSerie(data: any): void;
getTrianglePath1(x: number, y: number, length: number): string;
getTrianglePath(x: number, y: number, length: number): string;
getTrianglePath(x: number, y: number, length: number, options?: {
max: number;
min: number;
}): string;
getBarOpacity(rowValues: RowValues): number;
mergeMacthedSeriesAndSort(matchedSeries: any[]): any;
get seriesUniqKeys(): string[];

47260
dist/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/types.d.ts vendored

@ -10,6 +10,8 @@ export declare type BarOptionsParams = {
barWidth: number;
maxBarWidth: number;
minBarWidth: number;
maxAnnotationSize: number;
minAnnotationSize: number;
matching: boolean;
opacityFormatter: (data: RowValues) => number;
annotations: {

8
dist/utils.d.ts vendored

@ -0,0 +1,8 @@
/**
* Finds the closest item to a given number in an array using binary search
* @argument arr: ascending sorted array
* @argument num: number to find
* @returns index of the closest item to `num`
* @returns -1 if given array is empty
*/
export declare function findClosest(arr: number[], num: number): number;

5702
package-lock.json generated

File diff suppressed because it is too large Load Diff

87
src/index.ts

@ -1,6 +1,7 @@
import { ChartwerkPod, VueChartwerkPodMixin, TickOrientation, TimeFormat, AxisFormat } from '@chartwerk/core';
import { BarTimeSerie, BarOptions, RowValues } from './types';
import { findClosest } from './utils';
import * as d3 from 'd3';
import * as _ from 'lodash';
@ -14,6 +15,7 @@ const DEFAULT_BAR_OPTIONS: BarOptions = {
export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
barYScale: null | d3.ScaleLinear<number, number> = null;
_seriesDataForRendring = [];
constructor(el: HTMLElement, _series: BarTimeSerie[] = [], _options: BarOptions = {}) {
super(d3, el, _series, _options);
@ -27,17 +29,23 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
}
this.setBarPodScales();
this.setSeriesDataForRendering();
this.renderSerie(this._seriesDataForRendring);
}
if(this.options.matching === false || this.seriesUniqKeys.length === 0) {
const zippedData = this.getZippedDataForRender(this.visibleSeries);
this.renderSerie(zippedData);
return;
get isMatchingDisabled(): boolean {
return this.options.matching === false || this.seriesUniqKeys.length === 0;
}
setSeriesDataForRendering(): void {
if(this.isMatchingDisabled) {
this._seriesDataForRendring = this.getZippedDataForRender(this.visibleSeries);
} else {
const matchedSeries = this.seriesForMatching.map(
(series: BarTimeSerie[], idx: number) => this.getZippedDataForRender(series)
);
this._seriesDataForRendring = this.mergeMacthedSeriesAndSort(matchedSeries);
}
const matchedSeries = this.seriesForMatching.map((series: BarTimeSerie[], idx: number) => {
return this.getZippedDataForRender(series);
});
const concatedSeries = this.mergeMacthedSeriesAndSort(matchedSeries);
this.renderSerie(concatedSeries);
}
setBarPodScales(): void {
@ -89,16 +97,17 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
.attr('d', () => {
const x = Math.ceil(_.toNumber(rectSelection.attr('x')));
const y = Math.ceil(_.toNumber(rectSelection.attr('y')));
return this.getTrianglePath1(x, y, this.barWidth);
const options = { max: this.options.maxAnnotationSize, min: this.options.minAnnotationSize };
return this.getTrianglePath(x, y, this.barWidth, options);
})
.attr('fill', annotation.color);
});
}
getTrianglePath1(x: number, y: number, length: number): string {
getTrianglePath(x: number, y: number, length: number, options?: { max: number, min: number }): string {
// (x, y) - top left corner of bar
const minTriangleSize = 6;
const maxTriagleSize = 10;
const minTriangleSize = options?.min || 6;
const maxTriagleSize = options?.max || 10;
const yOffset = 4; // offset between triangle and bar
const centerX = x + length / 2;
const correctedLength = _.clamp(length, minTriangleSize, maxTriagleSize);
@ -122,36 +131,6 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
L ${bottomMiddleCorner.x} ${bottomMiddleCorner.y} z`;
}
getTrianglePath(x: number, y: number, length: number): string {
// (x, y) - top left corner
const Y_OFFSET = 2;
const correctedY = Math.max(y, Y_OFFSET);
const correctedLength = length <= 10 ? length : 10;
let x1 = x - Y_OFFSET;
let x2 = x + length + Y_OFFSET;
let x1x2Len = x2 - x1;
let y1 = correctedY - Y_OFFSET;
let yM = correctedY + length - Y_OFFSET;
if (x1x2Len > correctedLength) {
const xDiff = x1x2Len - correctedLength;
x1 += xDiff / 2;
x2 -= xDiff / 2;
const yDiff = yM - y1;
if (xDiff < yDiff) {
y1 += (yDiff - xDiff) + Y_OFFSET*3;
}
}
const x3 = x + length / 2;
return `M ${x1} ${y1}
L ${x2} ${y1}
L ${x3} ${yM} z`;
}
getBarOpacity(rowValues: RowValues): number {
if(this.options.opacityFormatter === undefined) {
return 1;
@ -254,29 +233,15 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
}
}
// TODO: not any[]
getSeriesPointFromMousePosition(eventX: number): any[] | undefined {
if(this.series === undefined || this.series.length === 0) {
return undefined;
}
const mouseDate = Math.ceil(this.xScale.invert(eventX));
const zippedData = this.getZippedDataForRender(this.visibleSeries);
// get the nearest RowValues element for mouseDate
const keys = _.map(zippedData, 'key').sort((a, b) => (a - mouseDate) - (mouseDate - b));
const idx = _.findIndex(zippedData, (a) => a.key == keys[0]);
const series: any[] = [];
for(let i = 0; i < zippedData[idx].values.length; i++) {
const mousePoisitionKey = Math.ceil(this.xScale.invert(eventX));
const keys = _.map(this._seriesDataForRendring, el => el.key);
const idx = findClosest(keys, mousePoisitionKey);
series.push({
value: zippedData[idx].key,
xval: zippedData[idx].values[i],
color: zippedData[idx].colors[i],
label: zippedData[idx].serieTarget[i]
});
}
return series;
return this._seriesDataForRendring[idx];
}
getBarColor(serie: any) {

2
src/types.ts

@ -11,6 +11,8 @@ export type BarOptionsParams = {
barWidth: number; // width in x axis unit
maxBarWidth: number; // in px
minBarWidth: number; // in px
maxAnnotationSize: number; // in px TODO: move to annotaions
minAnnotationSize: number; // in px
matching: boolean;
opacityFormatter: (data: RowValues) => number;
annotations: {

29
src/utils.ts

@ -0,0 +1,29 @@
/**
* Finds the closest item to a given number in an array using binary search
* @argument arr: ascending sorted array
* @argument num: number to find
* @returns index of the closest item to `num`
* @returns -1 if given array is empty
*/
export function findClosest(arr: number[], num: number): number {
if(arr.length === 0) {
return -1;
}
let lowIdx = 0;
let highIdx = arr.length - 1;
while(highIdx - lowIdx > 1) {
const midIdx = Math.floor((lowIdx + highIdx) / 2);
if(arr[midIdx] < num) {
lowIdx = midIdx;
} else {
highIdx = midIdx;
}
}
if(num - arr[lowIdx] <= arr[highIdx] - num) {
return lowIdx;
}
return highIdx;
}
Loading…
Cancel
Save