Skip to content

Instantly share code, notes, and snippets.

@c5inco
Created February 14, 2022 04:48
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save c5inco/c2d360909216618064fdcc7ed410617e to your computer and use it in GitHub Desktop.
Save c5inco/c2d360909216618064fdcc7ed410617e to your computer and use it in GitHub Desktop.
Marching ants effect on Compose logo paths. Inspired by: https://twitter.com/amos_gyamfi/status/1492595384362967042
package des.c5inco.material3
import android.graphics.Matrix
import androidx.compose.animation.core.*
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import des.c5inco.material3.ui.theme.Theme.Companion.Material3Theme
@Preview
@Composable
fun ComposeLogo() {
Material3Theme(true, false) {
Surface(Modifier.fillMaxSize()) {
Box(
contentAlignment = Alignment.Center
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
val infiniteTransition = rememberInfiniteTransition()
val logoSizeModifier = Modifier.size(width = 143.dp, height = 160.dp)
Text("figma vector")
Spacer(Modifier.height(16.dp))
Box {
ComposeFigma(
modifier = logoSizeModifier,
color = MaterialTheme.colorScheme.primary,
strokeWidth = 8f,
dashOffset = floatArrayOf(40f, 20f),
phase = animatedPhase(
transition = infiniteTransition,
duration = 2000,
phase = 60f
)
)
ComposeFigma(
modifier = logoSizeModifier.scale(0.5f),
color = MaterialTheme.colorScheme.tertiary,
strokeWidth = 72f,
dashOffset = floatArrayOf(200f, 100f),
phase = animatedPhase(
transition = infiniteTransition,
duration = 10000,
phase = 300f
),
)
}
Spacer(Modifier.height(32.dp))
Text("exported svg")
Spacer(Modifier.height(16.dp))
Box {
ComposeLogo(
modifier = logoSizeModifier,
color = MaterialTheme.colorScheme.primary,
strokeWidth = 8f,
dashOffset = floatArrayOf(40f, 20f),
phase = animatedPhase(
transition = infiniteTransition,
duration = 2000,
phase = 60f
)
)
ComposeLogo(
modifier = logoSizeModifier.scale(0.5f),
color = MaterialTheme.colorScheme.tertiary,
strokeWidth = 72f,
dashOffset = floatArrayOf(200f, 100f),
phase = animatedPhase(
transition = infiniteTransition,
duration = 10000,
phase = 300f
),
)
}
}
}
}
}
}
@Composable
private fun ComposeFigma(
modifier: Modifier,
color: Color,
strokeWidth: Float,
dashOffset: FloatArray,
phase: Float
) {
Canvas(
modifier
) {
/*
* Path drawn with raw Figma shapes
*/
val baseWidth = 86.6025390625f
val baseHeight = 96.90599060058594f
val path = Path()
path.fillType = PathFillType.EvenOdd
path.moveTo(39.9711f, 5.185f)
path.lineTo(7f, 24.2209f)
path.cubicTo(5.1436f, 25.2927f, 4f, 27.2735f, 4f, 29.4171f)
path.lineTo(4f, 67.4889f)
path.cubicTo(4f, 69.6325f, 5.1436f, 71.6132f, 7f, 72.685f)
path.lineTo(39.9711f, 91.7209f)
path.cubicTo(41.8275f, 92.7927f, 44.1147f, 92.7927f, 45.9711f, 91.7209f)
path.lineTo(78.9423f, 72.685f)
path.cubicTo(80.7987f, 71.6132f, 81.9423f, 69.6325f, 81.9423f, 67.4889f)
path.lineTo(81.9423f, 29.4171f)
path.cubicTo(81.9423f, 27.2735f, 80.7987f, 25.2927f, 78.9423f, 24.2209f)
path.lineTo(45.9711f, 5.185f)
path.cubicTo(44.1147f, 4.1132f, 41.8275f, 4.1132f, 39.9711f, 5.185f)
path.close()
drawPath(
path = path
.asAndroidPath()
.apply {
transform(Matrix().apply {
setScale(size.width / baseWidth, size.height / baseHeight)
})
}
.asComposePath(),
color = color,
style = Stroke(
width = strokeWidth,
cap = StrokeCap.Round,
join = StrokeJoin.Round,
pathEffect = PathEffect.dashPathEffect(dashOffset, phase)
)
)
}
}
@Composable
private fun ComposeLogo(
modifier: Modifier,
color: Color,
strokeWidth: Float,
dashOffset: FloatArray,
phase: Float
) {
Canvas(
modifier
) {
/*
* Path drawn with Compose logo
*/
val baseWidth = 143.2519989013672f
val baseHeight = 160.31832885742188f
val path = Path()
path.moveTo(72.044f, 160.3178f)
path.cubicTo(69.144f, 160.3418f, 66.29f, 159.6038f, 63.765f, 158.1778f)
path.lineTo(5.578f, 125.3118f)
path.cubicTo(2.162f, 123.3888f, 0.041f, 119.7848f, 0.003f, 115.8688f)
path.lineTo(0.001f, 49.0388f)
path.cubicTo(-0.027f, 46.1818f, 0.538f, 43.4288f, 1.698f, 41.0038f)
path.cubicTo(2.945f, 38.3968f, 4.88f, 36.1718f, 7.515f, 34.6148f)
path.lineTo(62.292f, 2.3008f)
path.cubicTo(64.796f, 0.8218f, 67.645f, 0.0288f, 70.552f, 0.0008f)
path.cubicTo(73.461f, -0.0272f, 76.324f, 0.7108f, 78.856f, 2.1408f)
path.lineTo(134.233f, 33.4188f)
path.cubicTo(136.702f, 34.8148f, 138.864f, 36.7858f, 140.446f, 39.1188f)
path.cubicTo(142.171f, 41.6508f, 143.222f, 44.6018f, 143.252f, 47.6828f)
path.lineTo(143.251f, 111.2808f)
path.cubicTo(143.278f, 114.1888f, 142.54f, 117.0518f, 141.11f, 119.5838f)
path.cubicTo(139.681f, 122.1158f, 137.61f, 124.2268f, 135.106f, 125.7048f)
path.lineTo(80.328f, 158.0238f)
path.cubicTo(77.772f, 159.5348f, 74.909f, 160.2938f, 72.043f, 160.3178f)
path.lineTo(72.044f, 160.3178f)
path.close()
drawPath(
path = path
.asAndroidPath()
.apply {
transform(Matrix().apply {
setScale(size.width / baseWidth, size.height / baseHeight)
})
}
.asComposePath(),
color = color,
style = Stroke(
width = strokeWidth,
cap = StrokeCap.Round,
join = StrokeJoin.Round,
pathEffect = PathEffect.dashPathEffect(dashOffset, phase)
)
)
}
}
@Composable
private fun animatedPhase(
transition: InfiniteTransition,
duration: Int = 1000,
phase: Float
): Float {
val animatedPhase by transition.animateFloat(
initialValue = phase,
targetValue = -phase,
animationSpec = infiniteRepeatable(
animation = tween(duration, easing = LinearEasing),
)
)
return animatedPhase
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment