@@ -286,44 +286,46 @@ fun LineChart(
286286 )
287287 val pathData = linesPathData[index]
288288
289-
290- val showOnPointsThreshold =
291- ((properties.mode as ? PopupProperties .Mode .PointMode )?.threshold
292- ? : 0 .dp).toPx()
293- val pointX =
294- pathData.xPositions.find { it in positionX - showOnPointsThreshold.. positionX + showOnPointsThreshold }
295- if (properties.mode !is PopupProperties .Mode .PointMode || pointX != null ) {
296- val fraction =
297- ((if (properties.mode is PopupProperties .Mode .PointMode ) (pointX?.toFloat()
298- ? : 0f ) else positionX) / size.width)
299- val popupValue = getPopupValue(
300- points = line.values,
301- fraction = fraction.toDouble(),
302- rounded = line.curvedEdges ? : curvedEdges,
303- size = _size ,
304- minValue = minValue,
305- maxValue = maxValue
306- )
307- popups.add(
308- Popup (
309- position = popupValue.offset,
310- value = popupValue.calculatedValue,
311- properties = properties
289+ if (positionX >= pathData.xPositions[pathData.startIndex] && positionX <= pathData.xPositions[pathData.endIndex]) {
290+ val showOnPointsThreshold =
291+ ((properties.mode as ? PopupProperties .Mode .PointMode )?.threshold
292+ ? : 0 .dp).toPx()
293+ val pointX =
294+ pathData.xPositions.find { it in positionX - showOnPointsThreshold.. positionX + showOnPointsThreshold }
295+
296+ if (properties.mode !is PopupProperties .Mode .PointMode || pointX != null ) {
297+ val fraction =
298+ ((if (properties.mode is PopupProperties .Mode .PointMode ) (pointX?.toFloat()
299+ ? : 0f ) else positionX) / size.width)
300+ val popupValue = getPopupValue(
301+ points = line.values,
302+ fraction = fraction.toDouble(),
303+ rounded = line.curvedEdges ? : curvedEdges,
304+ size = _size ,
305+ minValue = minValue,
306+ maxValue = maxValue
312307 )
313- )
314-
315- if (popupsOffsetAnimators.count() < popups.count()) {
316- repeat(popups.count() - popupsOffsetAnimators.count()) {
317- popupsOffsetAnimators.add(
318- // add fixed position for popup when mode is point mode
319- if (properties.mode is PopupProperties .Mode .PointMode ) {
320- Animatable (popupValue.offset.x) to Animatable (
321- popupValue.offset.y
322- )
323- } else {
324- Animatable (0f ) to Animatable (0f )
325- }
308+ popups.add(
309+ Popup (
310+ position = popupValue.offset,
311+ value = popupValue.calculatedValue,
312+ properties = properties
326313 )
314+ )
315+
316+ if (popupsOffsetAnimators.count() < popups.count()) {
317+ repeat(popups.count() - popupsOffsetAnimators.count()) {
318+ popupsOffsetAnimators.add(
319+ // add fixed position for popup when mode is point mode
320+ if (properties.mode is PopupProperties .Mode .PointMode ) {
321+ Animatable (popupValue.offset.x) to Animatable (
322+ popupValue.offset.y
323+ )
324+ } else {
325+ Animatable (0f ) to Animatable (0f )
326+ }
327+ )
328+ }
327329 }
328330 }
329331 }
@@ -357,12 +359,18 @@ fun LineChart(
357359 }
358360 if (linesPathData.isEmpty() || linesPathData.count() != data.count()) {
359361 data.map {
362+ val startIndex = if (it.viewRange.startIndex < 0 || it.viewRange.startIndex >= it.values.size - 1 ) 0 else it.viewRange.startIndex
363+ val endIndex = if (it.viewRange.endIndex < 0 || it.viewRange.endIndex <= it.viewRange.startIndex
364+ || it.viewRange.endIndex > it.values.size - 1 ) it.values.size - 1 else it.viewRange.endIndex
365+
360366 getLinePath(
361367 dataPoints = it.values.map { it.toFloat() },
362368 maxValue = maxValue.toFloat(),
363369 minValue = minValue.toFloat(),
364370 rounded = it.curvedEdges ? : curvedEdges,
365- size = size.copy(height = chartAreaHeight)
371+ size = size.copy(height = chartAreaHeight),
372+ startIndex,
373+ endIndex
366374 )
367375 }.also {
368376 linesPathData.addAll(it)
@@ -405,13 +413,26 @@ fun LineChart(
405413 brush = line.color,
406414 style = Stroke (width = stroke, pathEffect = pathEffect)
407415 )
416+
417+ var startOffset = 0f
418+ var endOffset = size.width
419+ if (pathData.startIndex > 0 ) {
420+ startOffset = pathData.xPositions[pathData.startIndex] .toFloat()
421+ }
422+
423+ if (pathData.endIndex < line.values.size - 1 ) {
424+ endOffset = pathData.xPositions[pathData.endIndex].toFloat()
425+ }
426+
408427 if (line.firstGradientFillColor != null && line.secondGradientFillColor != null ) {
409428 drawLineGradient(
410429 path = pathData.path,
411430 color1 = line.firstGradientFillColor,
412431 color2 = line.secondGradientFillColor,
413432 progress = line.gradientProgress.value,
414- size = size.copy(height = chartAreaHeight)
433+ size = size.copy(height = chartAreaHeight),
434+ startOffset,
435+ endOffset
415436 )
416437 } else if (line.drawStyle is DrawStyle .Fill ) {
417438 var fillColor = Color .Unspecified
@@ -423,7 +444,9 @@ fun LineChart(
423444 color1 = fillColor,
424445 color2 = fillColor,
425446 progress = 1f ,
426- size = size.copy(height = chartAreaHeight)
447+ size = size.copy(height = chartAreaHeight),
448+ startOffset,
449+ endOffset
427450 )
428451 }
429452
@@ -440,7 +463,9 @@ fun LineChart(
440463 minValue = minValue.toFloat(),
441464 pathMeasure = pathMeasure,
442465 scope = scope,
443- size = size.copy(height = chartAreaHeight)
466+ size = size.copy(height = chartAreaHeight),
467+ startIndex = pathData.startIndex,
468+ endIndex = pathData.endIndex
444469 )
445470 }
446471 }
@@ -509,7 +534,7 @@ private fun DrawScope.drawPopup(
509534 textMeasurer : TextMeasurer ,
510535 scope : CoroutineScope ,
511536 progress : Float ,
512- offsetAnimator : Pair <Animatable <Float , AnimationVector1D >, Animatable <Float , AnimationVector1D >>? = null,
537+ offsetAnimator : Pair <Animatable <Float , AnimationVector1D >, Animatable <Float , AnimationVector1D >>? = null
513538) {
514539 val offset = popup.position
515540 val popupProperties = popup.properties
@@ -615,6 +640,8 @@ fun DrawScope.drawDots(
615640 pathMeasure : PathMeasure ,
616641 scope : CoroutineScope ,
617642 size : Size ? = null,
643+ startIndex : Int ,
644+ endIndex : Int ,
618645) {
619646 val _size = size ? : this .size
620647
@@ -623,47 +650,49 @@ fun DrawScope.drawDots(
623650 pathMeasure.setPath(linePath, false )
624651 val lastPosition = pathMeasure.getPosition(pathMeasure.length)
625652 dataPoints.forEachIndexed { valueIndex, value ->
626- val dotOffset = Offset (
627- x = _size .width.spaceBetween(
628- itemCount = dataPoints.count(),
629- index = valueIndex
630- ),
631- y = (_size .height - calculateOffset(
632- maxValue = maxValue.toDouble(),
633- minValue = minValue.toDouble(),
634- total = _size .height,
635- value = value.second
636- )).toFloat()
653+ if (valueIndex in startIndex.. endIndex) {
654+ val dotOffset = Offset (
655+ x = _size .width.spaceBetween(
656+ itemCount = dataPoints.count(),
657+ index = valueIndex
658+ ),
659+ y = (_size .height - calculateOffset(
660+ maxValue = maxValue.toDouble(),
661+ minValue = minValue.toDouble(),
662+ total = _size .height,
663+ value = value.second
664+ )).toFloat()
637665
638- )
639- if (lastPosition != Offset .Unspecified && lastPosition.x >= dotOffset.x - 20 || ! properties.animationEnabled) {
640- if (! value.first.isRunning && properties.animationEnabled && value.first.value != 1f ) {
641- scope.launch {
642- value.first.animateTo(1f , animationSpec = properties.animationSpec)
666+ )
667+ if (lastPosition != Offset .Unspecified && lastPosition.x >= dotOffset.x - 20 || ! properties.animationEnabled) {
668+ if (! value.first.isRunning && properties.animationEnabled && value.first.value != 1f ) {
669+ scope.launch {
670+ value.first.animateTo(1f , animationSpec = properties.animationSpec)
671+ }
643672 }
644- }
645673
646- val radius: Float
647- val strokeRadius: Float
648- if (properties.animationEnabled) {
649- radius =
650- (properties.radius.toPx() + properties.strokeWidth.toPx() / 2 ) * value.first.value
651- strokeRadius = properties.radius.toPx() * value.first.value
652- } else {
653- radius = properties.radius.toPx() + properties.strokeWidth.toPx() / 2
654- strokeRadius = properties.radius.toPx()
674+ val radius: Float
675+ val strokeRadius: Float
676+ if (properties.animationEnabled) {
677+ radius =
678+ (properties.radius.toPx() + properties.strokeWidth.toPx() / 2 ) * value.first.value
679+ strokeRadius = properties.radius.toPx() * value.first.value
680+ } else {
681+ radius = properties.radius.toPx() + properties.strokeWidth.toPx() / 2
682+ strokeRadius = properties.radius.toPx()
683+ }
684+ drawCircle(
685+ brush = properties.strokeColor,
686+ radius = radius,
687+ center = dotOffset,
688+ style = Stroke (width = properties.strokeWidth.toPx(), pathEffect = pathEffect),
689+ )
690+ drawCircle(
691+ brush = properties.color,
692+ radius = strokeRadius,
693+ center = dotOffset,
694+ )
655695 }
656- drawCircle(
657- brush = properties.strokeColor,
658- radius = radius,
659- center = dotOffset,
660- style = Stroke (width = properties.strokeWidth.toPx(), pathEffect = pathEffect),
661- )
662- drawCircle(
663- brush = properties.color,
664- radius = strokeRadius,
665- center = dotOffset,
666- )
667696 }
668697 }
669698}
0 commit comments