Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render images instead of circles for data points in ScatterChart #983

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,5 +1,6 @@
package com.github.wuxudong.rncharts.charts;

import android.content.Context;

import com.facebook.react.uimanager.ThemedReactContext;
import com.github.mikephil.charting.charts.ScatterChart;
Expand All @@ -16,9 +17,12 @@ public String getName() {
return "RNScatterChart";
}

Context context;

@Override
protected ScatterChart createViewInstance(ThemedReactContext reactContext) {
ScatterChart scatterChart = new ScatterChart(reactContext);
context = reactContext;
scatterChart.setOnChartValueSelectedListener(new RNOnChartValueSelectedListener(scatterChart));
scatterChart.setOnChartGestureListener(new RNOnChartGestureListener(scatterChart));
return scatterChart;
Expand All @@ -27,6 +31,8 @@ protected ScatterChart createViewInstance(ThemedReactContext reactContext) {

@Override
DataExtract getDataExtract() {
return new ScatterDataExtract();
ScatterDataExtract dataExtract = new ScatterDataExtract();
dataExtract.context = context;
return dataExtract;
}
}
@@ -1,5 +1,7 @@
package com.github.wuxudong.rncharts.data;

import android.content.Context;

import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
Expand Down
@@ -1,5 +1,7 @@
package com.github.wuxudong.rncharts.data;

import android.content.Context;

import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
Expand Down Expand Up @@ -27,6 +29,7 @@ LineData createData() {
return new LineData();
}

public Context context;

@Override
IDataSet<Entry> createDataSet(ArrayList<Entry> entries, String label) {
Expand Down Expand Up @@ -112,7 +115,8 @@ Entry createEntry(ReadableArray values, int index) {
ReadableMap bundle = icon.getMap("bundle");
int width = icon.getInt("width");
int height = icon.getInt("height");
entry = new Entry(x, (float) map.getDouble("y"), DrawableUtils.drawableFromUrl(bundle.getString("uri"), width, height));
entry = new Entry(x, (float) map.getDouble("y"), DrawableUtils.drawableFromUrl(context, bundle.getString("uri"), width, height), ConversionUtil.toMap(map));


} else {
entry = new Entry(x, (float) map.getDouble("y"), ConversionUtil.toMap(map));
Expand Down
@@ -1,5 +1,7 @@
package com.github.wuxudong.rncharts.data;

import android.content.Context;

import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
Expand All @@ -12,7 +14,9 @@
import com.github.wuxudong.rncharts.utils.BridgeUtils;
import com.github.wuxudong.rncharts.utils.ChartDataSetConfigUtils;
import com.github.wuxudong.rncharts.utils.ConversionUtil;
import com.github.wuxudong.rncharts.utils.DrawableUtils;

import java.lang.Exception;
import java.util.ArrayList;
import java.util.Locale;

Expand All @@ -25,6 +29,8 @@ ScatterData createData() {
return new ScatterData();
}

public Context context;

@Override
IDataSet<Entry> createDataSet(ArrayList<Entry> entries, String label) {
return new ScatterDataSet(entries, label);
Expand Down Expand Up @@ -63,7 +69,17 @@ Entry createEntry(ReadableArray values, int index) {
if (map.hasKey("x")) {
x = (float) map.getDouble("x");
}
entry = new Entry(x, (float) map.getDouble("y"), ConversionUtil.toMap(map));

if (map.hasKey("icon")) {
ReadableMap icon = map.getMap("icon");
ReadableMap bundle = icon.getMap("bundle");
int width = icon.getInt("width");
int height = icon.getInt("height");
entry = new Entry(x, (float) map.getDouble("y"), DrawableUtils.drawableFromUrl(context, bundle.getString("uri"), width, height), ConversionUtil.toMap(map));

} else {
entry = new Entry(x, (float) map.getDouble("y"), ConversionUtil.toMap(map));
}
} else if (ReadableType.Number.equals(values.getType(index))) {
entry = new Entry(x, (float) values.getDouble(index));
} else {
Expand Down
@@ -1,5 +1,6 @@
package com.github.wuxudong.rncharts.utils;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
Expand All @@ -8,19 +9,28 @@
import android.graphics.drawable.ShapeDrawable;
import android.os.AsyncTask;

import com.github.wuxudong.rncharts.BuildConfig;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class DrawableUtils {
public static Drawable drawableFromUrl(String url, final int width, final int height) {
try {
return new DrawableLoadingAsyncTask().execute(url, Integer.toString(width), Integer.toString(height)).get();
} catch (Exception e) {
// draw dummy drawable when execution fail
e.printStackTrace();
return new ShapeDrawable();
public static Drawable drawableFromUrl(Context context, String url, final int width, final int height) {
if (BuildConfig.BUILD_TYPE == "debug") {
try {
return new DrawableLoadingAsyncTask().execute(url, Integer.toString(width), Integer.toString(height)).get();
} catch (Exception e) {
// draw dummy drawable when execution fail
e.printStackTrace();
return new ShapeDrawable();
}
} else {
int resourceId = context.getResources().getIdentifier(url, "drawable", context.getPackageName());

Bitmap image = BitmapFactory.decodeResource(context.getResources(), resourceId);
return new BitmapDrawable(Resources.getSystem(), Bitmap.createScaledBitmap(image, width, height, true));
}
}

Expand Down
53 changes: 52 additions & 1 deletion ios/ReactNativeCharts/scatter/ScatterDataExtract.swift
Expand Up @@ -10,6 +10,7 @@ import Foundation

import SwiftyJSON
import DGCharts
import UIKit

class ScatterDataExtract : DataExtract {
override func createData() -> ChartData {
Expand Down Expand Up @@ -53,17 +54,40 @@ class ScatterDataExtract : DataExtract {

if value.dictionary != nil {
let dict = value;
var y = Double(index);

if dict["x"].double != nil {
x = Double((dict["x"].doubleValue));
}

if dict["y"].number != nil {
entry = ChartDataEntry(x: x, y: dict["y"].doubleValue, data: dict as AnyObject?);
y = dict["y"].doubleValue;
} else {
fatalError("invalid data " + values.description);
}

if dict["icon"].exists() {
let icon = dict["icon"]
if icon["bundle"].dictionary != nil {
let bundle = icon["bundle"];

let uiImage = RCTConvert.uiImage(bundle.dictionaryObject);
let width = CGFloat(icon["width"].numberValue)/2.5;
let height = CGFloat(icon["height"].numberValue)/2.5;

if let image = uiImage {
let realIconImage = resizeImage(image: image, width: width, height: height);
entry = ChartDataEntry(x: x, y: dict["y"].doubleValue, icon: realIconImage, data: dict as AnyObject?);
} else {
entry = ChartDataEntry(x: x, y: dict["y"].doubleValue, icon: uiImage, data: dict as AnyObject?);
}

} else {
entry = ChartDataEntry(x: x, y: dict["y"].doubleValue, data: dict as AnyObject?);
}
} else {
entry = ChartDataEntry(x: x, y: dict["y"].doubleValue, data: dict as AnyObject?);
}

} else if value.double != nil {
entry = ChartDataEntry(x: x, y: value.doubleValue);
Expand All @@ -73,4 +97,31 @@ class ScatterDataExtract : DataExtract {

return entry;
}

func resizeImage(image: UIImage, width: CGFloat, height: CGFloat) -> UIImage {
let targetSize = CGSize(width: width, height: height)
let size = image.size

let widthRatio = targetSize.width / size.width
let heightRatio = targetSize.height / size.height

// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
} else {
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
}

// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

return newImage!
}
}
7 changes: 6 additions & 1 deletion lib/ChartDataConfig.js
Expand Up @@ -217,7 +217,12 @@ const scatterData = PropTypes.shape({
PropTypes.shape({
x: PropTypes.number,
y: PropTypes.number.isRequired,
marker: PropTypes.string
marker: PropTypes.string,
icon: PropTypes.shape({
bundle: PropTypes.object,
width: PropTypes.number,
height: PropTypes.number
})
}),
PropTypes.number
])
Expand Down