Google Maps Polyline not Appearing - flutter

I am trying to have several polylines appear in my GoogleMaps widget of my Flutter Dart Android app, yet they do not appear. The widget and map appear perfectly, but the Polylines are absent.
When my code runs, a polyline is successfully added to _polylines, and the GoogleMaps widget contains "polylines: _polylines", they they still wont show up.
Any thoughts?
My code appears as below:
class TotalStatsViewModel extends BaseViewModel {
final _navigationService = locator<NavigationService>();
Set<Polyline> _polylines = HashSet<Polyline>();
GoogleMapController mapController;
Widget getWidget() {
if (getLoggedInUser().activityList.length != 0) {
return Column(
children: [
getMap(),
Text(
'Total Distance Biked:',
textScaleFactor: 2,
),
Text(
getTotalDistance(),
textScaleFactor: 1.5,
),
Text(
'Total Duration Biked:',
textScaleFactor: 2,
),
Text(
getTotalDuration(),
textScaleFactor: 1.5,
),
Text(
'Average Biking Speed:',
textScaleFactor: 2,
),
Text(
getAverageSpeed(),
textScaleFactor: 1.5,
),
Spacer(),
Padding(
padding: const EdgeInsets.all(10.0),
child: ElevatedButton(
onPressed: () {
routeToHubView();
},
child: Text('Return'),
)),
Row(), //Row is here to center the column by adding a max width element.
],
);
} else {
return Column(
children: [
Text(
'User needs at least one added activity to display statistics.',
textScaleFactor: 1.5,
textAlign: TextAlign.center,
),
Spacer(),
Padding(
padding: const EdgeInsets.all(10.0),
child: ElevatedButton(
onPressed: () {
routeToHubView();
},
child: Text('Return'),
)),
Row(), //Row is here to center the column by adding a max width element.
],
);
}
}
Widget getMap() {
for (int i = 0; i < getLoggedInUser().activityList.length; i++) {
constructPolyline(getLoggedInUser().activityList[i]);
}
return SizedBox(
height: 300,
child: GoogleMap(
mapType: MapType.normal,
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
//target: LatLng(45.521563, -122.677433),
target: LatLng(47.6645740, -122.0411640),
zoom: 11.0,
),
polylines: _polylines,
),
);
}
void constructPolyline(Activity activity) {
print('CONSTRUCT POLYLINE CALLED');
List<LatLng> polylineLatLongs = [];
//fix with activity
Gpx gpx = GpxReader().fromString('<?xml version="1.0" encoding="UTF-8"?>'
'<gpx creator="StravaGPX" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3">'
'<metadata>'
'<time>2022-02-06T21:22:54Z</time>'
'</metadata>'
'<trk>'
'<name>Afternoon Ride</name>'
'<type>1</type>'
'<trkseg>'
'<trkpt lat="47.6645740" lon="-122.0411640">'
'<ele>113.0</ele>'
'<time>2022-02-06T21:22:54Z</time>'
'<extensions>'
'<power>0</power>'
'<gpxtpx:TrackPointExtension>'
'<gpxtpx:atemp>22</gpxtpx:atemp>'
'<gpxtpx:hr>85</gpxtpx:hr>'
'<gpxtpx:cad>37</gpxtpx:cad>'
'</gpxtpx:TrackPointExtension>'
'</extensions>'
'</trkpt>'
'<trkpt lat="47.6645750" lon="-122.0411670">'
'<ele>128.0</ele>'
'<time>2022-02-06T21:22:55Z</time>'
'<extensions>'
'<power>0</power>'
'<gpxtpx:TrackPointExtension>'
'<gpxtpx:atemp>22</gpxtpx:atemp>'
'<gpxtpx:hr>87</gpxtpx:hr>'
'<gpxtpx:cad>37</gpxtpx:cad>'
'</gpxtpx:TrackPointExtension>'
'</extensions>'
'</trkpt>');
//debug code
print('trks: ' + gpx.trks.length.toString());
print('trksegs: ' + gpx.trks[0].trksegs.length.toString());
print('trkpts: ' + gpx.trks[0].trksegs[0].trkpts.length.toString());
for (int i = 0; i < gpx.trks.length; i++) {
for (int j = 0; j < gpx.trks[i].trksegs.length; j++) {
for (int k = 0; k < gpx.trks[i].trksegs[j].trkpts.length; k++) {
polylineLatLongs.add(LatLng(gpx.trks[i].trksegs[j].trkpts[k].lat,
gpx.trks[i].trksegs[j].trkpts[k].lon));
print('ITERATION DONE');
}
}
}
print(polylineLatLongs.toString());
//polylineLatLongs.add(LatLng(47.664574, -122.041164));
//polylineLatLongs.add(LatLng(47.664575, -122.041167));
_polylines.add(Polyline(
polylineId: PolylineId('0'),
points: polylineLatLongs,
color: Colors.red,
visible: true,
width: 10));
print(_polylines.toString());
}
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
}
String getTotalDistance() {
User user = getLoggedInUser();
double distanceSum = 0;
for (int i = 0; i < user.activityList.length; i++) {
distanceSum += user.activityList[i].distance;
}
distanceSum = double.parse((distanceSum).toStringAsFixed(2));
return distanceSum.toString() + ' miles';
}
String getTotalDuration() {
User user = getLoggedInUser();
int totalSeconds = 0;
for (int i = 0; i < user.activityList.length; i++) {
totalSeconds += user.activityList[i].duration.inSeconds;
}
Duration totalDuration = Duration(seconds: totalSeconds);
List<String> splitDistance = totalDuration.toString().split('.');
return splitDistance[0];
}
String getAverageSpeed() {
User user = getLoggedInUser();
double avgSpeed = 0;
for (int i = 0; i < user.activityList.length; i++) {
avgSpeed += user.activityList[i].avgerageSpeed;
}
avgSpeed /= user.activityList.length;
avgSpeed = double.parse((avgSpeed).toStringAsFixed(2));
return avgSpeed.toString() + ' miles per hour';
}
void routeToHubView() {
_navigationService.navigateTo(HubViewRoute);
}
}

Use this code:
Set<Polyline> _directionPolyline = {};
Polyline polyLine = Polyline(
polylineId: const PolylineId('direction'),
color: Colors.blue,
points: List.empty(growable: true),
width: 5,
startCap: Cap.roundCap,
endCap: Cap.roundCap,
jointType: JointType.round,
geodesic: true,
);
polyLine.points.add(LatLng(element.latitude, element.longitude));
polyLine.points.add(LatLng(element.latitude, element.longitude));
_directionPolyline.add(polyLine);
And please rearrange the code... I just give the snippets.
return SizedBox(
height: 300,
child: GoogleMap(
mapType: MapType.normal,
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
//target: LatLng(45.521563, -122.677433),
target: LatLng(47.6645740, -122.0411640),
zoom: 11.0,
),
polylines: _directionPolyline,
),
)

Related

flutter app crashed when adding multi thousands points to Polygon

I used nominatim OpenStreetMap API to recieve coordinate of london city and try to draw polygon of london city, but cause the number of points is too alot when I use this code
try {
await state.getLocationPolygonByAddress(
state.foundedAddress[index].address);
var foundedSvg = state.foundedSvg;
List<LatLng> list = [];
setState(() {
testPolygon.points.clear();
});
for (int i = 0; i < foundedSvg.length; i++) {
for (int j = 0; j <
foundedSvg[i].geojson.coordinates
.length; j++) {
for (int k =0;k<foundedSvg[i].geojson.coordinates[j].length;k++)
{
for (int z = 0; z <
foundedSvg[i].geojson.coordinates[j][k]
.length; z++) {
/* if(foundedSvg[i].geojson
.coordinates[j][k].first is double &&
foundedSvg[i].geojson
.coordinates[j][k].last is double) {*/
list.add(LatLng(foundedSvg[i].geojson
.coordinates[j][k].first,
foundedSvg[i].geojson
.coordinates[j][k].last));
/* }
else{
print(k);
}*/
}
}
}
}
print(list.length);
state.clearfoundedAddress();
setState(() {
testPolygon.points.addAll(list);
});
print('polyeditor length: ${polyEditor.points.length}');
}catch(e){
print('error :'+e.toString());
}
and when try to add list of points to polygon in this line
testPolygon.points.addAll(list);
app crashed .
but it work good If the number of points is small.
this is my FlutterMap layer
late PolyEditor polyEditor;
List<Polygon> polygons = [];
// LatLngBounds boundingBox = LatLngBounds();
var testPolygon = Polygon(
color: Colors.black.withOpacity(0.3),
points: [],
borderColor: Colors.black,
isFilled: true,
borderStrokeWidth: 1.0);
#override
void initState() {
super.initState();
// processData();
polyEditor = PolyEditor(
addClosePathMarker: true,
points: testPolygon.points,
pointIcon: const Icon(
Icons.lens,
size: 10,
color: Colors.black,
),
intermediateIcon: const Icon(Icons.lens, size: 10, color:
Colors.black),
callbackRefresh: () => {setState(() {})},
);
polygons.add(testPolygon);
}
SearchController searchController = Get.put(SearchController());
MapController controller = MapController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
alignment: Alignment.center,
children: [
Center(
child: FlutterMap(
mapController: controller,
options: MapOptions(
// bounds: LatLngBounds(),
allowPanningOnScrollingParent: false,
onTap: (_, ll) {
print(ll);
polyEditor.add(testPolygon.points, ll);
},
plugins: [
DragMarkerPlugin(),
],
center: LatLng(32.5231, 51.6765),
zoom: 4.0,
),
layers: [
TileLayerOptions(
urlTemplate:
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c']),
PolygonLayerOptions(polygons: polygons,polygonCulling:
true),
DragMarkerPluginOptions(markers: polyEditor.edit(),),
],
),
),
the result should be like this
result picture
I want a result like this link
Yes this problem solved by deleting import ' package:flutter_map_line_editor/polyeditor.dart'; and delete this lines
DragMarkerPluginOptions(markers: polyEditor.edit(),),
polyEditor = PolyEditor(
addClosePathMarker: true,
points: testPolygon.points,
pointIcon: const Icon(
Icons.lens,
size: 10,
color: Colors.black,
),
intermediateIcon: const Icon(Icons.lens, size: 10, color: Colors.black),
callbackRefresh: () => {setState(() {})},
);`
in code
#lan say correct answer

Flutter: How to rotate diagonally a rect within a plane to paint

I have a word search app in which I use Rect to paint over a grid.
I have a gesture detector that allows me to identify which grid fields have been selected, through the global key and using onPanStart, onPanUpdate and onPanEnd I can see all the words that have been marked.
Everything works fine though, I don't know how to add a diagonal marker.
I currently get this result:
I would like to implement this diagonal painting
Demonstration of how the marking is currently, ps: The Gesture Detector still needs to be improved for painting, diagonally
I tried to add the RotationTransition, but the behavior didn't look good, below.
RotationTransition(
alignment: Alignment.centerLeft,
turns: new AlwaysStoppedAnimation(45 / 360),
child: Container(
padding: const EdgeInsets.all(2.0),
child: DecoratedBox(
decoration: BoxDecoration(
color: colorSelection!.withOpacity(0.4),
border: Border.all(
color: colorSelection!.withOpacity(0.1),
//width: width,
),
borderRadius: BorderRadius.circular(radius),
),
),
),
)
An overview of the important parts
Widget build(BuildContext context) {
return Stack(
children: [
GridView.count(
physics: NeverScrollableScrollPhysics(),
childAspectRatio: letterWidth / letterHeight,
crossAxisCount: nCols,
children: puzzle.asMap().map(
(index, letter) => MapEntry(
index,
BoardLetter(
letter,
isSelected: selection.contains(index),
isHit: hitIndexes.contains(index),
key: uniqueLetters[index]['key'],
),
),
)
.values
.toList(),
),
...markers,
Positioned(
width: widget.width,
height: widget.height,
child: RotationTransition(
turns: new AlwaysStoppedAnimation(360 / 360),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onPanStart: onPanStart,
onPanEnd: onPanEnd,
onPanUpdate: onPanUpdate,
),
),
),
],
);
Selection checks words and markers.last paints areas.
void onPanUpdate(DragUpdateDetails details) {
final currentIndex = computeLetterIndex(details.localPosition);
if(currentIndex >= 0 && currentIndex <= 99){
final key = uniqueLetters[currentIndex]['key'];
final RenderBox renderBox = key.currentContext.findRenderObject();
print("render box size ${renderBox.localToGlobal(Offset.zero, ancestor: context.findRenderObject())}");
markerRect = renderBox.localToGlobal(Offset.zero, ancestor: context.findRenderObject()) & renderBox.size;
List<int> _selection = [];
if (checkSameRow(startIndex, currentIndex)) {
if(direction == "horizontal"){
markers.last = adjustedMarker(markers.last, markerRect!);
_selection = genSelection(startIndex, currentIndex, 1);
}
} else if (checkSameCol(startIndex, currentIndex)) {
//print("direction $direction");
if(direction == "vertical"){
markers.last = adjustedMarker(markers.last, markerRect!);
_selection = genSelection(startIndex, currentIndex, nCols);
}
} else if (checkSameMainDiagonal(startIndex, currentIndex)) {
markers.last = adjustedMarker(markers.last, markerRect!);
_selection = genSelection(startIndex, currentIndex, nCols + 1);
} else if (checkSameCounterDiagonal(startIndex, currentIndex)) {
markers.last = adjustedMarker(markers.last, markerRect!);
_selection = genSelection(startIndex, currentIndex, nCols - 1);
}
setState(() {
selection = _selection;
});
}
}
It is checked if a word was found, otherwise it removes the paint(markers.last)
void onPanEnd(DragEndDetails details) {
final word = selection
.map((index) => puzzle[index])
.fold("", (dynamic value, letter) => value + letter);
// Check if this is a valid word
var reversedWord = word.split('').reversed.join();
var wordIndex = widget.words
.indexWhere((gameWord) => gameWord == word || gameWord == reversedWord);
if (wordIndex != -1) {
print("word $word/$reversedWord was hit");
widget.onHitWord(word, wordIndex);
this.setState(() {
direction = "";
colorNumber = colorNumber + 1 ;
hitIndexes = List.from(hitIndexes)..addAll(selection);
});
}else{
setState(() {
direction = "";
markers.removeLast();
selection = [];
});
}
}
The initial position is captured and marked.
void onPanStart(DragStartDetails details) {
startIndex = computeLetterIndex(details.localPosition);
final currentIndex = computeLetterIndex(details.localPosition);
final key = uniqueLetters[currentIndex]['key'];
final renderBox = key.currentContext.findRenderObject();
print(uniqueLetters[currentIndex]['letter']);
setState(() {
markerRect = renderBox.localToGlobal(Offset.zero, ancestor: context.findRenderObject()) & renderBox.size;
addMarker(markerRect, currentIndex);
});
}
The bookmark is added
void addMarker(Rect rect, int startIndex) {
markers.add(
WordMarker(
rect: rect,
startIndex: startIndex,
colorSelection: getColor(context),
color: getColor(context),
));
}
Markers are adjusted with rect
WordMarker adjustedMarker(WordMarker originalMarker, Rect endRect) {
originalMarker.colorSelection = getColor(context);
originalMarker.copyWith(rect: originalMarker.rect!.inflate(20.0));
return originalMarker.copyWith(rect: originalMarker.rect!.expandToInclude(endRect));
}

Flutter: How to insert Icon/Action based on X Y percent position of image

I want to insert a Icon/Action based on X Y percent position of image as follows:
This is Json file:
[
{
"seasonName": "Spring",
"isDaySelected": true,
"listButton": "Sky",
"pointXPercent": 66.0,
"pointYPercent": 12.0,
"pointName": "Bird",
"pointDialog": "this is a bird"
},
{
"seasonName": "Spring",
"isDaySelected": true,
"listButton": "Sky",
"pointXPercent": 53.6,
"pointYPercent": 27.4,
"pointName": "Cloud",
"pointDialog": "this is a cloud"
},
{
"seasonName": "Spring",
"isDaySelected": true,
"listButton": "Land",
"pointXPercent": 38.5,
"pointYPercent": 78.3,
"pointName": "Flower",
"pointDialog": "this is a flower"
},
{
"seasonName": "Spring",
"isDaySelected": false,
"listButton": "Land",
"pointXPercent": 55.3,
"pointYPercent": 79.8,
"pointName": "Meadow",
"pointDialog": "this is a meadow"
},
{
"seasonName": "Summer",
"isDaySelected": true,
"listButton": "Sky",
"pointXPercent": 38.9,
"pointYPercent": 23.5,
"pointName": "Sun",
"pointDialog": "this is the sun"
}
]
I want that when click on the TogglesButton "Sky" => get data from Json:
Get values seasonName = "Spring" (because TabBar is being
selected as "Spring")
Get values that satisfy (1) and have isDaySelected = "true" (because the TogglesButton isDaySelected is being selected as true)
Get values that satisfy (1) and (2) and listButton = "Sky"
Show the pointName values that satisfy (1) (2) (3) on image based on X Y percent. Ex:
pointName: "Bird" => pointXPercent = 66.0, pointYPercent = 12.0
pointName: "Cloud" => pointXPercent = 53.6, pointYPercent = 27.4
So pls help me, this is main file:
import 'package:ask/model/season_model.dart';
import 'package:ask/services/season_service.dart';
import 'package:flutter/material.dart';
class SeasonPage extends StatefulWidget {
SeasonPage() : super();
#override
_SeasonPageState createState() => _SeasonPageState();
}
class _SeasonPageState extends State<SeasonPage> {
List<Season> _season = [];
List<bool> isDaySelected = [true, false];
List<bool> listButton = [false, false, false];
final String springDay = 'https://i.imgur.com/MUuCuYI.png';
final String springNight = 'https://i.imgur.com/QxbAg8Y.png';
final String summerDay = 'https://i.imgur.com/9Qi6oLm.png';
final String summerNight = 'https://i.imgur.com/jrFGHvn.png';
final String autumnDay = 'https://i.imgur.com/yo0RWi6.png';
final String autumnNight = 'https://i.imgur.com/iPW4r2g.png';
final String winterDay = 'https://i.imgur.com/CnFDmEJ.png';
final String winterNight = 'https://i.imgur.com/lFNdvDe.png';
#override
void initState() {
super.initState();
SeasonServices.getSeason().then((seasons) {
setState(() {
_season = seasons;
});
});
}
#override
Widget build(BuildContext context) {
return Container(
child: DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
title: Text('Season'),
bottom: TabBar(tabs: [
Tab(child: Text('Spring')),
Tab(child: Text('Summer')),
Tab(child: Text('Autumn')),
Tab(child: Text('Winter')),
]),
),
body: Column(children: [
Center(
child: ToggleButtons(
children: [Text('Day'), Text('Night')],
onPressed: (int index) {
setState(() {
for (int buttonIndex = 0; buttonIndex < isDaySelected.length; buttonIndex++) {
if (buttonIndex == index) {
isDaySelected[buttonIndex] = true;
} else {
isDaySelected[buttonIndex] = false;
}
}
});
},
isSelected: isDaySelected)),
SizedBox(height: 5),
Center(
child: ToggleButtons(
children: [Text('Sky'), Text('Mountain'), Text('Land')],
onPressed: (int index) {
setState(() {
for (int buttonIndex = 0; buttonIndex < listButton.length; buttonIndex++) {
if (buttonIndex == index) {
listButton[buttonIndex] = !listButton[buttonIndex];
} else {
listButton[buttonIndex] = false;
}
}
});
},
isSelected: listButton)),
Expanded(
child: TabBarView(children: [
isDaySelected[0] ? Image.network(springDay) : Image.network(springNight),
isDaySelected[0] ? Image.network(summerDay) : Image.network(summerNight),
isDaySelected[0] ? Image.network(autumnDay) : Image.network(autumnNight),
isDaySelected[0] ? Image.network(winterDay) : Image.network(winterNight),
]),
)
]))));
}
}
There are several ways to achive result
Use Stack and wrap it in IntrinsicHeight to set it height as you image height
Column(
children: <Widget>[
IntrinsicHeight(
child: Stack(
children: <Widget>[
Image.network('https://i.imgur.com/MUuCuYI.png'),
Align(
alignment: Alignment(.66 * 2 - 1, .12 * 2 - 1),
child: Text('bird'),
),
Align(
alignment: Alignment(.536 * 2 - 1, .274 * 2 - 1),
child: Text('cloud'),
),
],
),
),
],
),
This will be sized to Stack children max height and until network image loaded(finally you know size) it will be tall as max of bird or cloud heigh
Note that IntrinsicHeight is relatively expensive. Avoid using it where possible.
For more complex cases you can use LayoutBuilder
body: Column(
children: <Widget>[
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return Stack(
children: <Widget>[
Positioned(
top: .12 * constraints.biggest.height,
left: .66 * constraints.biggest.width,
child: Text('bird'),
),
Positioned(
top: .274 * constraints.biggest.height,
left: .536 * constraints.biggest.width,
child: Text('cloud'),
),
],
);
},
),
),
],
),
PS Here we laying out by left&top of our bird&cloud
If you need to layout by center of birs&cloud - you have to know their sizes and do a little bit more math
You can use Align to choose the position in a stack like this:
Stack(children: [
child: Align(
alignment: Alignment(-.40, -.90),
child: MyPictureWidget()
),
]);
Nicer because you don't need to get the constraints. :) Alignment(0, 0) would be at the center

Flutter Linechart Widget not rebuilding on Data Changes with Provider using Change Notifier

ive currently got a screen that has a linechart widget this is a stateless widget that uses the Flchart plugin
the datasource for the linechart is uisng a provider that is listening for changes, i also have a Date filter that calls an api and gets the data for that date range and refreshes the data
what i am finding is when i refresh the data for a diffrent date range, i can see the data is being sent to the widget but the line chart is not rendering/rebuilt, if i switch back to the default date range the first loaded chart is displayed correctly.
line chart widget
class LineChartWidget extends StatelessWidget {
final List<FlSpot> list;
final bool isDollar;
LineChartWidget({this.list, this.isDollar});
final DateTime now = DateTime.now();
double minY = 0;
double maxY = 0;
#override
Widget build(BuildContext context) {
list.forEach((f) => print(f.y.toString()));
return list.isEmpty
? Container(
child: Center(
child: Text("No Chart Data..."),
),
)
: ConstrainedBox(
constraints: BoxConstraints.expand(height: 140),
child: LineChart(mainData()),
);
}
static int dse2mse(double daysSinceEpoch) {
return (daysSinceEpoch * 86400000).floor();
}
static double mse2dse(int millisecondsSinceEpoch) {
return millisecondsSinceEpoch / 86400000;
}
String getTitleFunction(double value) {
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(dse2mse(value));
return DateFormat('MMM d').format(dateTime);
}
LineChartData mainData() {
maxY = list[0].y;
minY = list[0].y;
list.forEach((i) {
if (i.y < minY) {
minY = i.y;
}
if (i.y > maxY) {
maxY = i.y;
}
});
return LineChartData(
minX: mse2dse(DateTime(now.year, now.month, 1).millisecondsSinceEpoch),
maxX: mse2dse(now.millisecondsSinceEpoch),
minY: minY - 1.9 * minY,
maxY: maxY + 0.2 * maxY,
clipToBorder: true,
gridData: FlGridData(
show: false,
),
titlesData: FlTitlesData(
show: false,
),
borderData: FlBorderData(
show: false,
),
lineTouchData: LineTouchData(
fullHeightTouchLine: false,
handleBuiltInTouches: true,
getTouchedSpotIndicator:
(LineChartBarData barData, List<int> spotIndexes) {
return spotIndexes.map((spotIndex) {
final FlSpot spot = barData.spots[spotIndex];
if (spot.x == 0 || spot.x == 30 || spot.x == 29) {
return null;
}
return TouchedSpotIndicatorData(
const FlLine(color: Colors.transparent, strokeWidth: 0),
const FlDotData(
dotSize: 5, dotColor: Color.fromRGBO(253, 54, 94, 1)),
);
}).toList();
},
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: Colors.white,
fitInsideHorizontally: true,
fitInsideVertically: true,
getTooltipItems: (List<LineBarSpot> touchedBarSpots) {
return touchedBarSpots.map((barSpot) {
final flSpot = barSpot;
if (flSpot.x == 0 || flSpot.x == 30 || flSpot.x == 29) {
return null;
}
return LineTooltipItem(
isDollar
? '${getTitleFunction(flSpot.x)} | \$${flSpot.y}'
: '${getTitleFunction(flSpot.x)} | ${flSpot.y.toStringAsFixed(0)}',
const TextStyle(
color: Colors.black87,
fontFamily: 'NeueMontreal',
letterSpacing: 0.9,
fontWeight: FontWeight.w600,
fontSize: 12),
);
}).toList();
})),
lineBarsData: [
LineChartBarData(
spots: list,
isCurved: true,
colors: [Color.fromRGBO(253, 54, 94, 1)],
curveSmoothness: 0.17,
barWidth: 1,
isStrokeCapRound: true,
dotData: const FlDotData(
show: false,
),
),
],
);
}
}
im not sure whether changing the linechart widget to Stateful would help as i cant call setstate because the data is being refreshed by NotifyListers automatically
thanks
Resolved the issue, with the line chart not upating, MinX and MaxX values need to be updated when the date range changes

Flutter: The getter 'Options' isn't defined for class 'Marker'

I know flutter has changed Google_Maps_api which is causing multiple errors in my code such as
1) 'Options' isn't defined for class 'Marker'
2) Too Many Positional Arguments : 0 expected 2 found
3) 'addMarker' isn't defined for class 'GoogleMapController'
4) 'clearMarker' isn't defined for class 'GoogleMapController'
I have checked this:
Flutter: How to add marker to Google Maps with new Marker API?
I am new to FLUTTER please help me solve these errors thanks
The Git I am using is :
https://github.com/code4func/flutter-taxiapp
import 'package:fl_uberapp/src/model/place_item_res.dart';
import 'package:fl_uberapp/src/model/step_res.dart';
import 'package:fl_uberapp/src/model/trip_info_res.dart';
import 'package:fl_uberapp/src/repository/place_service.dart';
import 'package:fl_uberapp/src/resources/widgets/car_pickup.dart';
import 'package:fl_uberapp/src/resources/widgets/home_menu.dart';
import 'package:fl_uberapp/src/resources/widgets/ride_picker.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
var _scaffoldKey = new GlobalKey<ScaffoldState>();
var _tripDistance = 0;
final Map<String, Marker> _markers = <String, Marker>{};
GoogleMapController _mapController;
#override
Widget build(BuildContext context) {
print("build UI");
return Scaffold(
key: _scaffoldKey,
body: Container(
constraints: BoxConstraints.expand(),
color: Colors.white,
child: Stack(
children: <Widget>[
GoogleMap(
// key: ggKey,
// markers: Set.of(markers.values),
onMapCreated: (GoogleMapController controller) {
_mapController = controller;
},
initialCameraPosition: CameraPosition(
target: LatLng(10.7915178, 106.7271422),
zoom: 14.4746,
),
),
Positioned(
left: 0,
top: 0,
right: 0,
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
title: Text(
"Taxi App",
style: TextStyle(color: Colors.black),
),
leading: FlatButton(
onPressed: () {
print("click menu");
_scaffoldKey.currentState.openDrawer();
},
child: Image.asset("ic_menu.png")),
actions: <Widget>[Image.asset("ic_notify.png")],
),
Padding(
padding: EdgeInsets.only(top: 20, left: 20, right: 20),
child: RidePicker(onPlaceSelected),
),
],
),
),
Positioned(left: 20, right: 20, bottom: 40,
height: 248,
child: CarPickup(_tripDistance),
)
],
),
),
drawer: Drawer(
child: HomeMenu(),
),
);
}
void onPlaceSelected(PlaceItemRes place, bool fromAddress) {
var mkId = fromAddress ? "from_address" : "to_address";
_addMarker(mkId, place);
_moveCamera();
_checkDrawPolyline();
}
void _addMarker(String mkId, PlaceItemRes place) async {
_addMarker(MarkerId, place);
// remove old
_markers.remove(mkId);
_mapController.clearMarkers();
_markers[mkId] = Marker(
mkId,
MarkerOptions(
position: LatLng(place.lat, place.lng),
infoWindowText: InfoWindowText(place.name, place.address)));
for (var m in _markers.values) {
await _mapController.addMarker(m.options);
}
}
void _moveCamera() {
print("move camera: ");
print(_markers);
if (_markers.values.length > 1) {
var fromLatLng = _markers["from_address"].options.position;
var toLatLng = _markers["to_address"].options.position;
var sLat, sLng, nLat, nLng;
if(fromLatLng.latitude <= toLatLng.latitude) {
sLat = fromLatLng.latitude;
nLat = toLatLng.latitude;
} else {
sLat = toLatLng.latitude;
nLat = fromLatLng.latitude;
}
if(fromLatLng.longitude <= toLatLng.longitude) {
sLng = fromLatLng.longitude;
nLng = toLatLng.longitude;
} else {
sLng = toLatLng.longitude;
nLng = fromLatLng.longitude;
}
LatLngBounds bounds = LatLngBounds(northeast: LatLng(nLat, nLng), southwest: LatLng(sLat, sLng));
_mapController.animateCamera(CameraUpdate.newLatLngBounds(bounds, 50));
} else {
_mapController.animateCamera(CameraUpdate.newLatLng(
_markers.values.elementAt(0).options.position));
}
}
void _checkDrawPolyline() {
// remove old polyline
_mapController.clearPolylines();
if (_markers.length > 1) {
var from = _markers["from_address"].options.position;
var to = _markers["to_address"].options.position;
PlaceService.getStep(
from.latitude, from.longitude, to.latitude, to.longitude)
.then((vl) {
TripInfoRes infoRes = vl;
_tripDistance = infoRes.distance;
setState(() {
});
List<StepsRes> rs = infoRes.steps;
List<LatLng> paths = new List();
for (var t in rs) {
paths
.add(LatLng(t.startLocation.latitude, t.startLocation.longitude));
paths.add(LatLng(t.endLocation.latitude, t.endLocation.longitude));
}
// print(paths);
_mapController.addPolyline(PolylineOptions(
points: paths, color: Color(0xFF3ADF00).value, width: 10));
});
}
}
}
Going through the errors that you've received, it seems that you're trying to call non-existent functions from the Objects that you're using.
'Options' isn't defined for class 'Marker' - checking Marker class from the docs, there's no options that you can call.
i.e.
_markers.values.elementAt(0).options.position
var from = _markers["from_address"].options.position;
var to = _markers["to_address"].options.position;
Too Many Positional Arguments : 0 expected 2 found - this error was thrown because there's two arguments that you're trying to use on the method that doesn't expect to receive an argument. Check which line this error was thrown.
As for the last two, GoogleMapController doesn't have addMarker() and clearMarker().
To add markers on GoogleMapController, you need to define markers on GoogleMap widget.
GoogleMap(
markers: Set<Marker>.of(_markers.values),
...
)
Other than that, the rest of the code seems fine.