Skip to content

Instantly share code, notes, and snippets.

@roipeker
Last active November 26, 2020 20:01
Show Gist options
  • Save roipeker/45bf283b37a3121e04c00aa0228e5dce to your computer and use it in GitHub Desktop.
Save roipeker/45bf283b37a3121e04c00aa0228e5dce to your computer and use it in GitHub Desktop.
graphx line button
/// utility just to open a URL in html.
/// include "url_launcher: any" in your pubspec dependencies.
import 'package:url_launcher/url_launcher.dart';
openUrl(String url) async {
await launch(url, forceSafariVC: true);
}
/// roipeker 2020
///
/// GraphX hover button line effect.
///
/// web demo:
/// https://roi-graphx-linebutton.surge.sh
///
/// source:
/// https://gist.github.com/roipeker/45bf283b37a3121e04c00aa0228e5dce
///
/// GraphX package: https://pub.dev/packages/graphx
///
import 'package:flutter/material.dart';
import 'package:graphx/graphx.dart';
import 'js_utils.dart';
class DemoButtonApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: Text(
'graphx hover button',
style: TextStyle(
fontSize: 12,
),
),
elevation: 0,
backgroundColor: Colors.black.withOpacity(.1),
),
body: Center(
child: SizedBox(
width: 140,
height: 120,
child: SceneBuilderWidget(
builder: () => SceneController.withLayers(
front: DemoButtonScene(),
),
),
),
),
bottomNavigationBar: Container(
height: 50,
color: Colors.black45,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
children: [
SizedBox(width: 12),
TextButton(
child: Text(
'graphx gist',
style: TextStyle(fontSize: 12),
),
onPressed: () {
openUrl(
'https://gist.github.com/roipeker/45bf283b37a3121e04c00aa0228e5dce');
},
),
],
),
),
),
);
}
}
final stageColor = Colors.grey.shade800;
class DemoButtonScene extends SceneRoot {
DemoButtonScene() {
config(autoUpdateAndRender: true, usePointer: true);
}
@override
void addedToStage() {
stage.color = stageColor.value;
var btn = Btn1(120, 60);
addChild(btn);
btn.x = stage.stageWidth / 2;
btn.y = stage.stageHeight / 2;
}
}
class Btn1 extends Sprite {
double w, h;
Path _oriPath;
PathMetric _metrics;
final _tweenTf = 0.0.twn;
final _tweenBg1 = 0.0.twn;
final _tweenBg2 = 0.0.twn;
final _stageColorTween = stageColor.twn;
Shape bg;
Shape bg2;
Shape bgBounds;
StaticText tf;
bool isOver = false;
Btn1([this.w = 100, this.h = 50]) {
_init();
}
void _init() {
bg = Shape();
bg.graphics
.lineStyle(.4, Colors.white.value)
.drawRect(0, 0, w, h)
.endFill();
bgBounds = Shape();
bgBounds.graphics.beginFill(0x0).drawRect(0, 0, w, h).endFill();
bgBounds.alpha = 0.001;
bg2 = Shape();
_oriPath = Path.from(bg.graphics.getPaths());
_metrics = _oriPath.computeMetrics(forceClosed: true).first;
tf = StaticText(
text: 'GRAPHX',
textStyle: StaticText.getStyle(
letterSpacing: 1,
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w100,
),
);
addChild(bg);
addChild(bg2);
addChild(bgBounds);
addChild(tf);
// mouseChildren = false;
tf.mouseEnabled = bg.mouseEnabled = bg2.mouseEnabled = false;
// bgBounds.mouseUseShape = false;
bgBounds.mouseEnabled = true;
bgBounds.useCursor = true;
bgBounds.onMouseDown.add((e) {
GTween.killTweensOf(tf);
GTween.killTweensOf(_openLink);
tf.tween(duration: .3, scale: .88);
stage.onMouseUp.addOnce((e) {
GTween.killTweensOf(tf);
tf.tween(duration: .5, scale: 1, ease: GEase.elasticOut);
if (isOver) {
GTween.delayedCall(1.2, _openLink);
}
});
});
bgBounds.onMouseOver.add((e) {
_tweenTo(true);
isOver = true;
bgBounds.onMouseOut.addOnce((e) {
isOver = false;
_tweenTo(false);
});
});
alignPivot();
tf.alignPivot();
tf.setPosition(w / 2, h / 2);
}
void _openLink() {
openUrl('https://pub.dev/packages/graphx');
}
void _tweenTo(bool enters) {
[
_tweenTf,
_tweenBg1,
_tweenBg2,
_stageColorTween,
].forEach(GTween.killTweensOf);
double value = enters ? 1.0 : 0.0;
/// tween background color.
_stageColorTween.target = _stageColorTween.value;
_stageColorTween.tween(
enters ? Colors.grey.shade900 : stageColor,
ease: GEase.easeOutSine,
duration: 1.1,
onUpdate: () {
stage.color = _stageColorTween.value.value;
},
);
_tweenTf.tween(value, duration: .4, onUpdate: _drawText);
_tweenBg1.tween(
value,
duration: .5,
onUpdate: _drawBg1,
);
_tweenBg2.tween(
value,
duration: enters ? 1.2 : .6,
delay: enters ? 0.2 : 0.0,
onUpdate: _drawBg2,
ease: GEase.easeOutExpo,
);
}
void _setStyle({
FontWeight fontWeight,
double letterSpacing,
Color color,
double fontSize,
}) {
tf.setTextStyle(StaticText.getStyle(
fontWeight: fontWeight,
fontSize: fontSize,
color: color,
letterSpacing: letterSpacing,
));
}
void _drawBg1() {
var percent = _tweenBg1.value;
var len = _metrics.length * (1 - percent);
var newPath = _metrics.extractPath(0, len);
bg.graphics.clear();
bg.graphics.lineStyle(.4 + (percent * 2.5), Colors.white.value);
bg.graphics.drawPath(newPath);
bg.graphics.endFill();
}
void _drawBg2() {
var from = _metrics.length - 90 * _tweenBg2.value;
var to = from + 20;
var newPath = _metrics.extractPath(from, to);
bg2.graphics.clear();
bg2.graphics.lineStyle(2 + _tweenBg2.value * 1, Colors.white.value);
bg2.graphics.drawPath(newPath);
bg2.graphics.endFill();
}
void _drawText() {
var variants = FontWeight.values;
var idx = (_tweenTf.value * (variants.length - 2)).round();
var weight = variants[idx];
_setStyle(
fontWeight: weight,
letterSpacing: _tweenTf.value,
color: Colors.white,
fontSize: 18,
);
tf.alignPivot();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment