Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Anderson, Danny H
gist-charts
Commits
8085b97b
Commit
8085b97b
authored
Aug 03, 2019
by
David Anderson
Browse files
charts are stable again with rxjs state
parent
0e5792aa
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
demo-angularIO/src/app/scatterchart-demo/scatterchart-demo.component.ts
View file @
8085b97b
...
...
@@ -18,18 +18,24 @@ export class ScatterChartDemoComponent implements AfterViewInit, OnDestroy {
ngAfterViewInit
()
{
const
me
=
this
;
me
.
chart
=
new
ChartCanvas
(
me
.
drawspace
.
nativeElement
);
const
pointCount
=
20
;
const
baseChart
=
new
ScatterChart
();
const
selectionChart
=
new
ScatterChart
();
me
.
chart
=
new
ChartCanvas
(
me
.
drawspace
.
nativeElement
);
baseChart
.
margin
=
5
;
selectionChart
.
margin
=
15
;
me
.
chart
.
debugLogger
.
logPrefix
=
'
Chart Canvas -
'
;
baseChart
.
debugLogger
.
logPrefix
=
'
Base Chart -
'
;
selectionChart
.
debugLogger
.
logPrefix
=
'
Selection Chart -
'
;
me
.
chart
.
debugLogger
.
isEnabled
=
true
;
// baseChart.debugLogger.isEnabled = true;
// selectionChart.debugLogger.isEnabled = true;
selectionChart
.
background
=
'
rgba(255,255,255,0.5)
'
;
// baseChart.onRenderStateChange = console.log;
selectionChart
.
background
=
'
rgba(255,255,255,0.1)
'
;
selectionChart
.
isActive
=
false
;
baseChart
.
getStyle
=
(
dp
:
DataPoint
<
ScatterData
>
)
=>
{
...
...
@@ -73,7 +79,11 @@ export class ScatterChartDemoComponent implements AfterViewInit, OnDestroy {
let
selectedData
:
DataPoint
[]
=
[];
baseChart
.
margin
=
5
;
selectionChart
.
datalist
(
selectedData
);
me
.
chart
.
addChart
(
[
baseChart
,
selectionChart
]
);
me
.
chart
.
addChart
(
[
baseChart
,
selectionChart
]
);
me
.
chart
.
addAxis
(
axis
);
const
getData
=
new
GetDataAtMouseEvent
(
'
click
'
,
...
...
demo-angularIO/src/styles.css
View file @
8085b97b
.text-center
{
text-align
:
center
;
text-align
:
center
;
}
.text-right
{
text-align
:
right
;
text-align
:
right
;
}
.nowrap
{
white-space
:
nowrap
;
white-space
:
nowrap
;
}
.chartList
{
padding-left
:
30px
;
padding-right
:
30px
;
padding-left
:
30px
;
padding-right
:
30px
;
}
.popover
{
padding
:
5px
;
border-radius
:
5px
;
display
:
block
;
padding
:
5px
;
border-radius
:
5px
;
display
:
block
;
}
.htmlBlock
.tag
{
color
:
steelblue
;
color
:
steelblue
;
}
.htmlBlock
.attr
{
color
:
seagreen
;
color
:
seagreen
;
}
.htmlBlock
.val
{
color
:
sandybrown
;
color
:
sandybrown
;
}
*
{
position
:
relative
;
margin
:
0
;
padding
:
0
;
position
:
relative
;
margin
:
0
;
padding
:
0
;
}
*,
*
:after
,
*
:before
{
box-sizing
:
inherit
;
box-sizing
:
inherit
;
}
svg
{
pointer-events
:
none
;
pointer-events
:
none
;
}
svg
*
{
pointer-events
:
all
;
pointer-events
:
all
;
}
body
,
html
{
position
:
relative
;
min-height
:
100%
;
height
:
100%
;
width
:
100%
;
overflow
:
hidden
;
box-sizing
:
border-box
;
font-family
:
'Open Sans'
,
sans-serif
;
font-size
:
18px
;
position
:
relative
;
min-height
:
100%
;
height
:
100%
;
width
:
100%
;
overflow
:
hidden
;
box-sizing
:
border-box
;
font-family
:
'Open Sans'
,
sans-serif
;
font-size
:
18px
;
}
router-outlet
{
display
:
none
;
display
:
none
;
}
button
{
cursor
:
pointer
;
font-family
:
'Open Sans'
,
sans-serif
;
background
:
#fff
;
color
:
#333
;
font-size
:
14px
;
padding
:
5px
10px
;
border-width
:
1px
;
cursor
:
pointer
;
font-family
:
'Open Sans'
,
sans-serif
;
background
:
#fff
;
color
:
#333
;
font-size
:
14px
;
padding
:
5px
10px
;
border-width
:
1px
;
}
input
{
padding
:
5px
;
padding
:
5px
;
}
a
{
cursor
:
pointer
;
text-decoration
:
none
;
color
:
#1f7cb6
;
cursor
:
pointer
;
text-decoration
:
none
;
color
:
#1f7cb6
;
}
header
{
padding-top
:
10px
;
padding-bottom
:
10px
;
padding-top
:
10px
;
padding-bottom
:
10px
;
}
header
h1
,
header
h2
,
header
h3
{
margin-top
:
0px
;
margin-bottom
:
0px
;
margin-top
:
0px
;
margin-bottom
:
0px
;
}
ul
,
li
{
list-style
:
none
;
list-style
:
none
;
}
ul
.bulleted
,
li
.bulleted
{
padding-left
:
10px
;
margin-left
:
10px
;
list-style
:
disc
;
padding-left
:
10px
;
margin-left
:
10px
;
list-style
:
disc
;
}
ul
.bulleted
ul
.bulleted
,
li
.bulleted
ul
.bulleted
,
ul
.bulleted
li
.bulleted
,
li
.bulleted
li
.bulleted
{
list-style
:
square
;
list-style
:
square
;
}
.chart
{
width
:
500px
;
height
:
500px
;
}
\ No newline at end of file
width
:
500px
;
height
:
500px
;
background
:
white
;
border-radius
:
5px
;
}
gist-charts/source/classes/chartCanvas.class.ts
View file @
8085b97b
import
{
combineLatest
,
Observable
}
from
'
rxjs
'
;
import
{
distinctUntilChanged
,
map
}
from
'
rxjs/operators
'
;
import
{
combineLatest
,
Observable
,
Subscription
}
from
'
rxjs
'
;
import
{
distinctUntilChanged
,
map
,
publishReplay
,
refCount
}
from
'
rxjs/operators
'
;
import
{
GistBehavior
}
from
'
../behaviors/gistBehavior.class
'
;
import
{
GistCanvas
}
from
'
../classes/gistCanvas.class
'
;
...
...
@@ -88,7 +88,9 @@ export class ChartCanvas {
private
animationFrame
:
number
=
0
;
private
areChartsRendering
!
:
Observable
<
boolean
>
;
public
areChartsRendering
:
Observable
<
boolean
>
|
undefined
;
private
activeStateChange
:
Observable
<
any
>
|
undefined
;
private
stateSubscription
:
Subscription
|
undefined
;
// private areAxisRending: Observable<boolean>;
// private isMainCanvasRendering: Observable<boolean>;
...
...
@@ -232,6 +234,9 @@ export class ChartCanvas {
me
.
chartList
.
forEach
(
(
chart
)
=>
{
chart
.
_implementation
.
stopDrawing
();
}
);
if
(
this
.
stateSubscription
)
{
this
.
stateSubscription
.
unsubscribe
();
}
}
/**
...
...
@@ -462,57 +467,43 @@ export class ChartCanvas {
chart
.
debugLogger
.
_log
(
'
INVALID CHART SIZE: CHART WILL NOT RENDER: chartWidth =
'
+
width
+
'
, chartHeight =
'
+
height
);
}
}
);
this
.
debugLogger
.
_log
(
'
starting chart config polling
'
);
me
.
pollCharts
();
}
this
.
debugLogger
.
_log
(
'
Charts now checking for data to draw
'
);
private
pollCharts
()
{
const
me
=
this
;
let
isDirty
=
false
;
me
.
pollPixelRatio
();
me
.
areChartsRendering
=
combineLatest
(
me
.
chartList
.
map
(
chart
=>
chart
.
_implementation
.
isRenderInProgress
)
).
pipe
(
map
(
array
=>
array
.
indexOf
(
false
)
===
-
1
),
distinctUntilChanged
()
me
.
areChartsRendering
=
combineLatest
(
me
.
chartList
.
map
(
chart
=>
chart
.
_implementation
.
isRenderInProgress
as
Observable
<
boolean
>
)
).
pipe
(
map
(
array
=>
array
.
indexOf
(
true
)
!==
-
1
),
distinctUntilChanged
(),
publishReplay
(
1
),
refCount
(),
);
me
.
areChartsRendering
.
subscribe
(
isRenderInProgress
=>
{
if
(
isRenderInProgress
)
{
isDirty
=
true
;
this
.
showCharts
();
}
else
if
(
isDirty
)
{
isDirty
=
false
;
this
.
copyCharts
();
}
}
)
me
.
activeStateChange
=
combineLatest
(
me
.
chartList
.
map
(
chart
=>
chart
.
_implementation
.
isActive
.
pipe
(
distinctUntilChanged
()
)
)
);
let
isDirty
=
true
;
this
.
stateSubscription
=
combineLatest
(
[
me
.
areChartsRendering
,
me
.
activeStateChange
]
)
.
subscribe
(
data
=>
{
let
areChartsRendering
=
data
[
0
];
me
.
debugLogger
.
_log
(
'
Render state changed
'
+
isDirty
);
if
(
areChartsRendering
)
{
this
.
showCharts
();
}
else
{
this
.
copyCharts
();
isDirty
=
false
;
}
}
)
}
private
pollPixelRatio
()
{
const
me
=
this
;
if
(
me
.
renderedRatio
!==
window
.
devicePixelRatio
)
{
me
.
debugLogger
.
_log
(
'
GistCharts is now redrawing due to pixel ratio change. This is normally caused by dragging changing computer monitors.
'
);
me
.
beginRender
();
}
// me.chartList.forEach( chart => {
// let canvas = chart._implementation.canvas;
// if ( chart.isActive ) {
// isRenderInProgress = isRenderInProgress || chart._implementation.isRenderInProgress;
// isDirty = isDirty || chart._implementation.isDirty;
// } else {
// canvas.canvasEle.style.visibility = 'hidden';
// }
// hasActiveChanged = hasActiveChanged || chart._implementation.hasActiveChanged;
// } );
// if ( isRenderInProgress ) {
// if ( !this._areRenderChartsShowing ) {
// this._areRenderChartsShowing = true;
// this.showCharts();
// }
// } else {
// this._areRenderChartsShowing = false;
// if ( isDirty || hasActiveChanged ) {
// this.copyCharts();
// }
// }
// me.animationFrame = window.requestAnimationFrame( () => { me.pollCharts(); } );
me
.
animationFrame
=
window
.
requestAnimationFrame
(
()
=>
{
me
.
pollPixelRatio
();
}
);
}
private
showCharts
()
{
...
...
@@ -546,8 +537,6 @@ export class ChartCanvas {
private
copyCharts
()
{
this
.
debugLogger
.
_log
(
'
copying charts over
'
);
const
me
=
this
;
const
rs
=
me
.
renderedSizes
;
let
cb
=
rs
.
chartBounds
;
me
.
canvas
.
clearCanvas
(
me
.
background
);
me
.
renderAxis
();
me
.
drawGridLines
();
...
...
@@ -566,22 +555,22 @@ export class ChartCanvas {
axis
.
_implementation
.
canvas
.
renderTo
(
me
.
canvas
.
canvasEle
,
x
,
y
);
}
);
let
cb
=
me
.
renderedSizes
.
chartBounds
;
me
.
chartList
.
forEach
(
chart
=>
{
if
(
chart
.
isActive
)
{
let
imp
=
chart
.
_implementation
;
let
margin
=
chart
.
margin
;
let
canvas
=
imp
.
canvas
;
let
imp
=
chart
.
_implementation
;
let
margin
=
chart
.
margin
;
let
canvas
=
imp
.
canvas
;
if
(
chart
.
isActive
)
{
canvas
.
renderTo
(
me
.
canvas
.
canvasEle
,
cb
.
left
-
margin
,
cb
.
top
-
margin
);
canvas
.
canvasEle
.
style
.
zIndex
=
'
-1
'
;
canvas
.
canvasEle
.
style
.
visibility
=
'
hidden
'
;
imp
.
isDirty
=
false
;
if
(
chart
.
debugLogger
.
isEnabled
)
{
let
progress
=
imp
.
getDrawProgress
();
chart
.
debugLogger
.
_log
(
'
chart copied with
'
+
progress
.
drawnCount
+
'
out of
'
+
progress
.
totalCount
+
'
datapoints
'
);
}
}
canvas
.
canvasEle
.
style
.
zIndex
=
'
-1
'
;
canvas
.
canvasEle
.
style
.
visibility
=
'
hidden
'
;
}
);
}
...
...
gist-charts/source/configs/charts/baseChart.class.ts
View file @
8085b97b
import
{
BehaviorSubject
}
from
'
rxjs
'
;
import
{
DataPoint
}
from
'
../../classes/datapoint.class
'
;
import
{
DebugLogger
}
from
'
../../classes/debugLogger.class
'
;
import
{
BaseChartImplementation
}
from
'
../../implementations/charts/baseChartImplementation.class
'
;
...
...
@@ -89,12 +87,13 @@ export abstract class BaseChart<T extends DataPoint = DataPoint> {
* @memberof BaseChart
*/
public
set
isActive
(
val
:
boolean
)
{
if
(
val
!==
this
.
_isActive
.
value
)
{
let
subject
=
this
.
_implementation
.
isActive
;
if
(
val
!==
subject
.
value
)
{
this
.
debugLogger
.
_log
(
'
chart isActive change
'
,
val
);
this
.
_isActive
.
next
(
val
);
subject
.
next
(
val
);
}
}
public
get
isActive
()
{
return
this
.
_isActive
.
value
;
}
public
get
isActive
()
{
return
this
.
_
implementation
.
isActive
.
value
;
}
/**
...
...
@@ -158,7 +157,6 @@ export abstract class BaseChart<T extends DataPoint = DataPoint> {
public
drawCountPerRender
:
number
=
100
;
private
_zIndex
:
number
|
undefined
;
private
_isActive
:
BehaviorSubject
<
boolean
>
=
new
BehaviorSubject
<
boolean
>
(
true
);
private
_background
:
string
|
undefined
;
}
gist-charts/source/implementations/charts/baseChartImplementation.class.ts
View file @
8085b97b
import
{
BehaviorSubject
,
Observable
}
from
'
rxjs
'
;
import
{
distinctUntilChanged
}
from
'
rxjs/operators
'
;
import
{
DataPoint
}
from
'
../../classes/datapoint.class
'
;
import
{
GistCanvas
}
from
'
../../classes/gistCanvas.class
'
;
...
...
@@ -93,7 +92,9 @@ export abstract class BaseChartImplementation {
* @memberof BaseChartImplementation
*/
private
_isRenderInProgress
:
BehaviorSubject
<
boolean
>
=
new
BehaviorSubject
<
boolean
>
(
false
);
public
isRenderInProgress
:
Observable
<
boolean
>
=
this
.
_isRenderInProgress
.
asObservable
().
pipe
(
distinctUntilChanged
()
);
public
isRenderInProgress
:
Observable
<
boolean
>
=
this
.
_isRenderInProgress
.
asObservable
();
public
isActive
:
BehaviorSubject
<
boolean
>
=
new
BehaviorSubject
<
boolean
>
(
true
);
/**
* This is used to let the chartCanvas it needs to recopy charts without this one.
...
...
@@ -196,23 +197,25 @@ export abstract class BaseChartImplementation {
*/
public
startDrawing
():
void
{
const
me
=
this
;
if
(
!
me
.
animationFrame
)
{
me
.
animationFrame
=
window
.
requestAnimationFrame
(
()
=>
{
if
(
this
.
chart
.
datalist
().
length
!==
this
.
drawnData
.
length
)
{
this
.
_isDirty
=
true
;
this
.
_isRenderInProgress
.
next
(
true
);
me
.
chart
.
debugLogger
.
_log
(
'
rendering new points, isDirty will be true without clearing
'
);
me
.
render
();
}
else
{
this
.
_isRenderInProgress
.
next
(
false
);
}
me
.
animationFrame
=
0
;
me
.
startDrawing
();
}
);
}
else
{
me
.
chart
.
debugLogger
.
_log
(
'
no longer rendering. datalist length:
'
+
this
.
chart
.
datalist
()
+
'
, drawn data length:
'
+
this
.
drawnData
.
length
);
}
if
(
me
.
animationFrame
)
return
;
me
.
animationFrame
=
window
.
requestAnimationFrame
(
()
=>
{
let
isRenderInProgress
=
this
.
chart
.
isActive
&&
this
.
drawnData
.
length
!==
this
.
chart
.
datalist
().
length
;
if
(
this
.
_isRenderInProgress
.
value
!==
isRenderInProgress
)
{
if
(
isRenderInProgress
)
{
me
.
chart
.
debugLogger
.
_log
(
'
new points detected:
'
+
this
.
drawnData
.
length
+
'
drawn out of
'
+
this
.
chart
.
datalist
().
length
);
}
else
{
me
.
chart
.
debugLogger
.
_log
(
'
rendering is done
'
);
}
this
.
_isRenderInProgress
.
next
(
isRenderInProgress
);
}
if
(
isRenderInProgress
)
{
this
.
_isDirty
=
true
;
me
.
render
();
}
me
.
animationFrame
=
0
;
me
.
startDrawing
();
}
);
}
/**
...
...
@@ -223,8 +226,10 @@ export abstract class BaseChartImplementation {
if
(
me
.
animationFrame
)
{
me
.
chart
.
debugLogger
.
_log
(
'
polling datalist stopped
'
);
window
.
cancelAnimationFrame
(
me
.
animationFrame
);
me
.
animationFrame
=
0
;
}
me
.
_isRenderInProgress
.
next
(
false
);
me
.
animationFrame
=
0
;
}
protected
onDataWipe
():
void
{
...
...
package/classes/chartCanvas.class.d.ts
View file @
8085b97b
import
{
Observable
}
from
'
rxjs
'
;
import
{
GistBehavior
}
from
'
../behaviors/gistBehavior.class
'
;
import
{
BaseAxis
}
from
'
../configs/axis/baseAxis.class
'
;
import
{
BaseChart
}
from
'
../configs/charts/baseChart.class
'
;
...
...
@@ -62,7 +63,9 @@ export declare class ChartCanvas {
private
renderedRatio
;
private
renderedSizes
;
private
animationFrame
;
private
areChartsRendering
;
areChartsRendering
:
Observable
<
boolean
>
|
undefined
;
private
activeStateChange
;
private
stateSubscription
;
constructor
(
container
:
HTMLElement
);
/**
* Add one or many charts to be rendered
...
...
@@ -147,7 +150,7 @@ export declare class ChartCanvas {
* @private
*/
private
renderCharts
();
private
poll
Charts
();
private
poll
PixelRatio
();
private
showCharts
();
private
drawGridLines
();
private
copyCharts
();
...
...
package/configs/charts/baseChart.class.d.ts
View file @
8085b97b
...
...
@@ -112,6 +112,5 @@ export declare abstract class BaseChart<T extends DataPoint = DataPoint> {
*/
drawCountPerRender
:
number
;
private
_zIndex
;
private
_isActive
;
private
_background
;
}
package/gistCharts.js
View file @
8085b97b
This source diff could not be displayed because it is too large. You can
view the blob
instead.
package/gistCharts.js.map
View file @
8085b97b
This diff is collapsed.
Click to expand it.
package/implementations/charts/baseChartImplementation.class.d.ts
View file @
8085b97b
import
{
Observable
}
from
'
rxjs
'
;
import
{
BehaviorSubject
,
Observable
}
from
'
rxjs
'
;
import
{
DataPoint
}
from
'
../../classes/datapoint.class
'
;
import
{
GistCanvas
}
from
'
../../classes/gistCanvas.class
'
;
import
{
BaseAxis
}
from
'
../../configs/axis/baseAxis.class
'
;
...
...
@@ -79,6 +79,7 @@ export declare abstract class BaseChartImplementation {
*/
private
_isRenderInProgress
;
isRenderInProgress
:
Observable
<
boolean
>
;
isActive
:
BehaviorSubject
<
boolean
>
;
/**
* This is used to let the chartCanvas it needs to recopy charts without this one.
* Will be set to true any time chart.isActive is toggled, will be set to false, when the chartCanvas copies it.
...
...
package/index.js
View file @
8085b97b
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment