Chart does not render with the new CN1aChartEngine library - codenameone
Here is the code:
public Component getCombinedTemperatureChart(Context context) {
/**
* Title for each line
*/
String[] titles = new String[]{"Temp 1", "Temp 2"};
/**
* x-axis values
*/
List<double[]> x = new ArrayList<double[]>();
for (int i = 0; i < titles.length; i++) {
x.add(new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
}
/**
* Value sets
*/
List<double[]> values = new ArrayList<double[]>();
values.add(new double[]{12.3, 12.5, 13.8, 16.8, 20.4, 24.4, 26.4, 26.1, 23.6, 20.3, 17.2,
13.9});
values.add(new double[]{9, 10, 11, 15, 19, 23, 26, 25, 22, 18, 13, 10});
/**
* Colors and Styles for renderer
*/
int[] colors = new int[]{Color.GREEN, Color.rgb(200, 150, 0)};
PointStyle[] styles = new PointStyle[]{PointStyle.CIRCLE, PointStyle.DIAMOND};
XYMultipleSeriesRenderer renderer = buildRenderer(colors, styles);
renderer.setPointSize(5.5f);
int length = renderer.getSeriesRendererCount();
for (int i = 0; i < length; i++) {
XYSeriesRenderer r = (XYSeriesRenderer) renderer.getSeriesRendererAt(i);
r.setLineWidth(5);
r.setFillPoints(true);
}
setChartSettings(renderer, "Weather data", "Month", "Temperature", 0.5, 12.5, 0, 40,
Color.LTGRAY, Color.LTGRAY);
renderer.setXLabels(12);
renderer.setYLabels(10);
renderer.setShowGrid(true);
renderer.setXLabelsAlign(Paint.Align.CENTER);
renderer.setYLabelsAlign(Paint.Align.RIGHT);
XYValueSeries sunSeries = new XYValueSeries("Demo 1");
sunSeries.add(1f, 35, 4.3);
sunSeries.add(2f, 35, 4.9);
sunSeries.add(3f, 35, 5.9);
sunSeries.add(4f, 35, 8.8);
sunSeries.add(5f, 35, 10.8);
sunSeries.add(6f, 35, 11.9);
sunSeries.add(7f, 35, 13.6);
sunSeries.add(8f, 35, 12.8);
sunSeries.add(9f, 35, 11.4);
sunSeries.add(10f, 35, 9.5);
sunSeries.add(11f, 35, 7.5);
sunSeries.add(12f, 35, 5.5);
XYSeriesRenderer lightRenderer = new XYSeriesRenderer();
lightRenderer.setColor(Color.YELLOW);
XYSeries waterSeries = new XYSeries("Demo 2");
waterSeries.add(1, 16);
waterSeries.add(2, 15);
waterSeries.add(3, 16);
waterSeries.add(4, 17);
waterSeries.add(5, 20);
waterSeries.add(6, 23);
waterSeries.add(7, 25);
waterSeries.add(8, 25.5);
waterSeries.add(9, 26.5);
waterSeries.add(10, 24);
waterSeries.add(11, 22);
waterSeries.add(12, 18);
XYSeries waterSeries2 = new XYSeries("Demo 3");
waterSeries2.add(1, 15);
waterSeries2.add(2, 14);
waterSeries2.add(3, 14);
waterSeries2.add(4, 15);
waterSeries2.add(5, 18);
waterSeries2.add(6, 22);
waterSeries2.add(7, 24);
waterSeries2.add(8, 25);
waterSeries2.add(9, 24);
waterSeries2.add(10, 21);
waterSeries2.add(11, 18);
waterSeries2.add(12, 16);
renderer.setBarSpacing(0.3);
XYSeriesRenderer sunSeries1 = new XYSeriesRenderer();
sunSeries1.setColor(0xff0011cc);
sunSeries1.setChartValuesTextAlign(Paint.Align.CENTER);
XYSeriesRenderer waterRenderer1 = new XYSeriesRenderer();
waterRenderer1.setColor(0xff0099cc);
waterRenderer1.setChartValuesTextAlign(Paint.Align.CENTER);
XYSeriesRenderer waterRenderer2 = new XYSeriesRenderer();
waterRenderer2.setColor(0xff9933cc);
waterRenderer2.setChartValuesTextAlign(Paint.Align.RIGHT);
XYMultipleSeriesDataset dataset = buildDataset(titles, x, values);
dataset.addSeries(0, sunSeries);
dataset.addSeries(0, waterSeries);
dataset.addSeries(0, waterSeries2);
renderer.addSeriesRenderer(0, lightRenderer);
renderer.addSeriesRenderer(0, waterRenderer1);
renderer.addSeriesRenderer(0, waterRenderer2);
renderer.setApplyBackgroundColor(true);
renderer.setBackgroundColor(Color.argb(50, 250, 210, 190));
waterRenderer1.setDisplayChartValues(true);
waterRenderer1.setChartValuesTextSize(10);
waterRenderer2.setDisplayChartValues(true);
waterRenderer2.setChartValuesTextSize(10);
ChartFactory.getLineChartView(context, dataset, renderer).setZoomRate(5f);
ChartFactory.getLineChartView(context, dataset, renderer).getCurrentSeriesAndPoint();
return ChartFactory.getLineChartView(context, dataset, renderer).getPeer();
}
This method returns chart as component. I called this method in the form of:
chart = demo.getCombinedTemperatureChart(context);
addComponent(BorderLayout.CENTER, chart);
With the older library the chart renders correctly but with the new library of CN1aChartEngine, I got this exception:
java.lang.NullPointerException
at org.achartengine.chart.XYChart.draw(XYChart.java:374)
at org.achartengine.GraphicalView.onDraw(GraphicalView.java:195)
at org.achartengine.compat.View$Peer.run(View.java:208)
at com.codename1.ui.Display$1.run(Display.java:775)
at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
[Task Thread] 0:0:0,0 - java.lang.NullPointerException
[Task Thread] 0:0:0,1 - java.lang.NullPointerException
While debugging I get that, this exception occurs when form.show() called not at the moment when the getCombinedTemperatureChart(Context context) method returns the chart component.
I didn't get why this exception occurs with the updated CN1aChartEngine library. Little help would be nice.
Looks like you're using the older 1.0.x line (i.e. using Pisces). I have reproduced the problem (in that line) and fixed it. You can download the latest at
https://github.com/shannah/CN1aChartEngine/releases/tag/1.0.2
Related
CryptoJS Encryption (AES)
my Code is written in Java, I want to use it into react-native, but I am not able to convert it properly in react native, I am stuck in it from last 36 hours. I am able to encrypt the code , but the apis are written and I have to create a replica of android app. input is : api/v1/master/Login/PinAuthentication expected output is : BiR6DnP2PDlLRiRxlaqzK/p+ysGnvL6SF2SCZEN/UbIBQwJ/eDQT8uLuZffcT+kl my react.js code is : var CryptoJS = require("crypto-js"); let workingURL = "BiR6DnP2PDlLRiRxlaqzK%2Fp%2BysGnvL6SF2SCZEN%2FUbIBQwJ%2FeDQT8uLuZffcT%2Bkl" let decryptedText = "BiR6DnP2PDlLRiRxlaqzK/p+ysGnvL6SF2SCZEN/UbIBQwJ/eDQT8uLuZffcT+kl" let appstring = "api/v1/master/Login/PinAuthentication" let appkey = "****************************************" //JFACzfbeLzsha7vB5vl3QMgnl3iYX06LWb3tjjnNTYQkV8ZMFg+xEtxY/uM8vEZk function encrypt10(){ let ciphertext = CryptoJS.enc.Utf8.parse(appstring) let secSpec = [-53, -96, -53, -96, -53, -92, -52, -95, -54, -92, -54, -91, -54, -88, -54, -89] let ivSpec = [-53, -96, -53, -96, -53, -92, -52, -95, -54, -92, -54, -91, -54, -88, -54, -89] ivSpec = CryptoJS.enc.Utf8.parse(appkey) secSpec = CryptoJS.enc.Utf8.parse(appkey) console.log("ciphertext : " + ciphertext) console.log("secSpec : " + secSpec) console.log("ivSpec : " + ivSpec) var encrypted = CryptoJS.AES.encrypt(ciphertext, secSpec, { iv: ivSpec, //yes I used password as iv too. Dont mind. mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, keySize: 128 / 8, }); console.log(encrypted.toString()); } to test it I am using react-js because of crypto-js library. private static byte[] getKeyBytes() throws UnsupportedEncodingException { byte[] keyBytes = new byte[16]; byte[] parameterKeyBytes = KEY.getBytes("UTF-8"); System.arraycopy(parameterKeyBytes, 0, keyBytes, 0, Math.min(parameterKeyBytes.length, keyBytes.length)); return keyBytes; } public static byte[] encrypt2(String value){ try{ byte[] keyBytes = getKeyBytes(); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec myKey = new SecretKeySpec(keyBytes, "AES"); IvParameterSpec IVKey = new IvParameterSpec(keyBytes); cipher.init(Cipher.ENCRYPT_MODE, myKey, IVKey); byte[] outputBytes = cipher.doFinal(value.getBytes("UTF-8")); return outputBytes; }catch(Exception err){ err.printStackTrace(); return null; } }
The main problem seems to me to be the derivation of the key. The Java code performs a UTF8 encoding of KEY and then uses the first 16 bytes as key. In the CryptoJS code, you also perform a UTF8 encoding of appkey (with CryptoJS.enc.Utf8.parse()), but then apply the entire data as key. You need to shorten the data, e.g. with secSpec.words.slice(0, 16/4)) and analogously for ivSpec, since you use the key as IV, which is insecure by the way. With this change, encryption works with the CryptoJS code and the ciphertext matches the expected result / the result of the Java Code (for the true key): let appstring = "api/v1/master/Login/PinAuthentication"; let appkey = "****************************************"; function encrypt10(){ let plaintext = CryptoJS.enc.Utf8.parse(appstring); let secSpec = CryptoJS.enc.Utf8.parse(appkey); let ivSpec = CryptoJS.enc.Utf8.parse(appkey); secSpec = CryptoJS.lib.WordArray.create(secSpec.words.slice(0, 16/4)); ivSpec = CryptoJS.lib.WordArray.create(ivSpec.words.slice(0, 16/4)); var encrypted = CryptoJS.AES.encrypt(plaintext, secSpec, {iv: ivSpec}); document.getElementById("ct").innerHTML = encrypted.toString(); } encrypt10(); <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script> <p style="font-family:'Courier New', monospace;" id="ct"></p> Regarding the key: More robust than a UTF8 decoding is a binary-to-text encoding like Base64 or hex.
EncodedImage failing to work on actual phone
I am facing a problem while using encodedImage. When a user logins into the app, the first form after successful login has an image. And the image is causing me issues upon retrieving it. When the user captures an image in the app, I convert it to a base64 string which I send to the server. The code for that is: ImageIO img = ImageIO.getImageIO(); ByteArrayOutputStream out = new ByteArrayOutputStream(); img.save(et, out, ImageIO.FORMAT_JPEG, 1); byte[] ba = out.toByteArray(); String userImage64 = Base64.encodeNoNewline(ba); et is the captured image. So I store the string userImage64 in the server. When I retrieve the base64, I decode it and convert it to an EncodedImage. The code is: String url = new JSONObject(result.getResponseData()).getString("photo"); byte[] b = Base64.decode(url.getBytes()); Image icon = EncodedImage.create(b); When I am on the simulator, everything flows smoothly. The images display and everything works very well. My issue is, when I put the app on an android device, it doesn't work. It shows me a toast of successful login and just stops there. So i did some debugging and realized that issue is with the three lines of converting from base64 to image. When I comment out the three lines, everything works very well. Where could I be going wrong? EDIT Below is the code I use to capture a photo: String i = Capture.capturePhoto(); if (i != null) { try { final Image newImage = Image.createImage(i); Image roundedMask = Image.createImage(rich.minScreensize() / 4, rich.minScreensize() / 4, 0xff000000); Graphics gra = roundedMask.getGraphics(); gra.setColor(0xffffff); gra.fillArc(0, 0, rich.minScreensize() / 4, rich.minScreensize() / 4, 0, 360); Object masked = roundedMask.createMask(); cropImage(newImage, rich.minScreensize() / 4, rich.minScreensize() / 4, et -> { if (editing) { try { ImageIO img = ImageIO.getImageIO(); ByteArrayOutputStream out = new ByteArrayOutputStream(); img.save(et, out, ImageIO.FORMAT_JPEG, 1); byte[] ba = out.toByteArray(); userImage64 = Base64.encodeNoNewline(ba); et = et.applyMask(masked); logoimage.setIcon(et); ///removed unnecessary code logoimage.getComponentForm().revalidate(); } catch (IOException ex) { } } else { et = et.applyMask(masked); logoimage.setIcon(et); } }); } catch (IOException ex) { Log.p("Error loading captured image from camera", Log.ERROR); } } Inside there is code I use to crop the photo and that is code is: private void cropImage(Image img, int destWidth, int destHeight, OnComplete<Image> s) { Form previous = getCurrentForm(); Form cropForm = new Form("", new LayeredLayout()); Label toobarLabel = new Label("New Holder", "Toolbar-HeaderLabel"); cropForm.setTitleComponent(toobarLabel); Toolbar mainToolbar = new Toolbar(); mainToolbar.setUIID("ToolBar"); cropForm.setToolbar(mainToolbar); Label moveAndZoom = new Label("Move and zoom the photo to crop it"); moveAndZoom.getUnselectedStyle().setFgColor(0xffffff); moveAndZoom.getUnselectedStyle().setAlignment(CENTER); moveAndZoom.setCellRenderer(true); cropForm.setGlassPane((Graphics g, Rectangle rect) -> { g.setColor(0x0000ff); g.setAlpha(150); Container cropCp = cropForm.getContentPane(); int posY = cropForm.getContentPane().getAbsoluteY(); GeneralPath p = new GeneralPath(); p.setRect(new Rectangle(0, posY, cropCp.getWidth(), cropCp.getHeight()), null); if (isPortrait()) { p.arc(0, posY + cropCp.getHeight() / 2 - cropCp.getWidth() / 2, cropCp.getWidth() - 1, cropCp.getWidth() - 1, 0, Math.PI * 2); } else { p.arc(cropCp.getWidth() / 2 - cropCp.getHeight() / 2, posY, cropCp.getHeight() - 1, cropCp.getHeight() - 1, 0, Math.PI * 2); } g.fillShape(p); g.setAlpha(255); g.setColor(0xffffff); moveAndZoom.setX(0); moveAndZoom.setY(posY); moveAndZoom.setWidth(cropCp.getWidth()); moveAndZoom.setHeight(moveAndZoom.getPreferredH()); moveAndZoom.paint(g); }); final ImageViewer viewer = new ImageViewer(); viewer.setImage(img); cropForm.add(viewer); cropForm.getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_CROP, e -> { previous.showBack(); s.completed(viewer.getCroppedImage(0). fill(destWidth, destHeight)); }); cropForm.getToolbar().addMaterialCommandToLeftBar("", FontImage.MATERIAL_CANCEL, e -> previous.showBack()); cropForm.show(); }
why my dataset.data's shape is different with each image?
I download the cifar10 dataset with torchvision for idx,(img,target) in enumerate(trainloader): print(trainloader.dataset.data.shape) print(img.shape) img = img.squeeze() img = torch.tensor(img) img=img.squeeze() print(img.shape) img = (img).permute(1, 2, 0) plt.imshow(img) plt.show() if idx==0:break But the print result is strange (50000, 32, 32, 3) torch.Size([1, 3, 224, 224]) torch.Size([3, 224, 224]) each image is size with (3,224,224) but the dataset.data's shape is (32,32,3)<br/> I want to make the dataset's shape with (500000,224,224,3) def load_data_cifar10(batch_size=128,test=False): if not test: train_dset = torchvision.datasets.CIFAR10(root='/mnt/3CE35B99003D727B/input/pytorch/data', train=True, download=True, transform=transform) else: train_dset = torchvision.datasets.CIFAR10(root='/mnt/3CE35B99003D727B/input/pytorch/data', train=False, download=True, transform=transform) train_loader = torch.utils.data.DataLoader(train_dset, batch_size=batch_size, shuffle=False) transform = transforms.Compose([ transforms.Resize(224), transforms.ToTensor(), ])
AnyChart - Live Streaming Stock Chart
I call a database that gives me the initial time interval data to create a OHLC stock chart in AnyChart. Live price updates are then streamed. What is the strategy about showing live price changes on the latest ticker? I've been trying to figure out how to use a set function from the view or data class but no luck with table data. Should I keep track of this newest interval and keep updating this row in AnyChart? When the interval is finished I drop the last one from the series and generate a new one?
If I caught your idea correctly, you're looking for an approach like the following one: anychart.onDocumentReady(function () { /* An interval ticker and random number generators simulate incoming data. For the demonstration purposes the time is “accelerated”. */ //create new point every 1 minute var period = 60000; //new price ticks come every 15 seconds var tickPeriod = 15000; var stage = anychart.graphics.create("container"); // create and tune the chart var chart = anychart.stock(); var plot = chart.plot(); grouping = chart.grouping(); //create OHLC series var ohlcSeries = plot.ohlc().name('OHLC'); // create dataset var dataset = anychart.data.table(); dataset.addData(getData()); //map data var mapping = dataset.mapAs({ x: 0, open: 1, high: 2, low: 3, close: 4 }); //set mapping to both series ohlcSeries.data(mapping); //render chart chart.container(stage).draw(); /* --- simulation code --- */ //create empty array for point data update var newDataRow = []; newDataRow[0] = new Array(5); //current price variable var price = null; //select the last point from existing datatable var selectable = mapping.createSelectable(); selectable.selectAll(); var iterator = selectable.getIterator(); while(iterator.advance()) { //put data from the last exsiting point newDataRow[0][0] = iterator.get('x'); newDataRow[0][1] = iterator.get('open'); newDataRow[0][2] = iterator.get('high'); newDataRow[0][3] = iterator.get('low'); newDataRow[0][5] = iterator.get('close'); } //timestamp variable for incoming ticks var newTimestamp = newDataRow[0][0]; //simulate price ticker window.setInterval(stream, 500); //updating chart handler function stream() { //get new price price = randomPrice(); //get timestamp of incoming price tick newTimestamp += tickPeriod; //current point update or create new point if (newTimestamp - newDataRow[0][0] <= period) { //set price as close for existing point newDataRow[0][4] = price; //update min and max if (newDataRow[0][2] < price) { newDataRow[0][2] = price; } else if (newDataRow[0][3] > price) { newDataRow[0][3] = price; } } else { //erase update data array newDataRow[0] = new Array(5); //set data for the new point newDataRow[0][0] = newTimestamp; newDataRow[0][1] = price; newDataRow[0][2] = price; newDataRow[0][3] = price; newDataRow[0][4] = price; } dataset.addData(newDataRow); } }); function randomPrice() { return (Math.random() * (24 - 22) + 22).toFixed(2); } function getData() { return [[1508889600000, 18.23, 19.36, 18.18, 19.31, 116002], [1508889660000, 19.5, 19.89, 19, 19.29, 113146], [1508889720000, 19.13, 19.15, 18.43, 18.75, 88690], [1508889780000, 18.54, 18.76, 18.27, 18.76, 80909], [1508889840000, 18.76, 19.14, 18.63, 18.76, 94782], [1508889900000, 18.97, 19.62, 18.96, 19.19, 133294], [1508889960000, 19.45, 19.7, 19.22, 19.67, 136209], [1508890020000, 19.69, 19.85, 19.37, 19.59, 136739], [1508890080000, 19.44, 19.55, 19, 19.35, 45322], [1508890140000, 19.21, 19.25, 18.51, 18.83, 37537], [1508890200000, 19.16, 19.78, 18.99, 19.76, 37994], [1508890260000, 19.69, 19.69, 19, 19.2, 114186], [1508890320000, 18.89, 18.95, 18.57, 18.61, 61185], [1508890380000, 18.59, 19.08, 18.57, 18.97, 40558], [1508890440000, 18.76, 19.19, 18.7, 18.78, 54007], [1508890500000, 18.92, 18.94, 18.47, 18.92, 65713], [1508890560000, 19.82, 21.2, 19.5, 20.91, 114016], [1508890620000, 20.55, 20.82, 20.28, 20.4, 100002], [1508890680000, 20.25, 20.27, 19.79, 19.93, 112040], [1508890740000, 20.11, 20.89, 20.06, 20.25, 106204], [1508890800000, 20.6, 21.1, 20.01, 20.26, 43234], [1508890860000, 20.19, 20.35, 19.86, 20.24, 45577], [1508890920000, 20.37, 20.4, 19.98, 20.19, 138514], [1508890980000, 20.14, 20.24, 19.64, 19.79, 15961], [1508891040000, 20.06, 20.07, 19.61, 19.79, 4816], [1508891100000, 19.96, 19.99, 19.14, 19.32, 42609], [1508891160000, 19.46, 19.64, 19.14, 19.42, 100893], [1508891220000, 19.2, 19.73, 19.01, 19.32, 106489], [1508891280000, 19.51, 20.06, 19.47, 19.89, 86507], [1508891340000, 19.92, 20, 19.67, 19.75, 122805], [1508891400000, 19.83, 20.23, 19.8, 20.06, 38734], [1508891460000, 20.13, 20.5, 19.98, 20.22, 128804], [1508891520000, 20.36, 20.6, 20.24, 20.6, 30999], [1508891580000, 20.51, 20.74, 20.25, 20.31, 45246], [1508891640000, 20.41, 20.69, 20.22, 20.38, 101014], [1508891700000, 20.14, 20.23, 19.51, 19.82, 119823], [1508891760000, 19.93, 20.17, 19.47, 19.75, 73663], [1508891820000, 19.54, 20.45, 19.45, 20.34, 56848], [1508891880000, 20.25, 20.6, 20.07, 20.13, 133059], [1508891940000, 20.32, 20.63, 20.05, 20.45, 41431], [1508892000000, 20.56, 20.94, 20.3, 20.89, 30151], [1508892060000, 21, 21.5, 20.86, 21.4, 82553], [1508892120000, 21.36, 21.98, 21.2, 21.4, 81917], [1508892180000, 21.31, 21.76, 21.29, 21.73, 52368], [1508892240000, 21.77, 21.9, 21.58, 21.83, 20181], [1508892300000, 21.96, 22.31, 21.81, 22.14, 112622], [1508892360000, 21.98, 22.32, 21.63, 22.05, 99857], [1508892420000, 22.06, 22.32, 21.88, 22.08, 105763], [1508892480000, 22.17, 22.62, 22.12, 22.55, 118968], [1508892540000, 22.59, 23.26, 22.57, 22.83, 12246], [1508892600000, 22.9, 23.38, 22.74, 23.33, 134378], [1508892660000, 23.23, 23.54, 23.02, 23.42, 117356], [1508892720000, 23.47, 24.11, 23.44, 23.45, 71104], [1508892780000, 23.5, 23.82, 23.17, 23.68, 44932], [1508892840000, 23.62, 23.69, 23.3, 23.5, 87991], [1508892900000, 24.04, 24.34, 23.75, 24.07, 91442], [1508892960000, 23.95, 23.95, 23.25, 23.28, 34895], [1508893020000, 23.38, 23.66, 23.21, 23.34, 88422], [1508893080000, 23.45, 23.75, 23.36, 23.47, 65606], [1508893140000, 23.43, 23.92, 23.2, 23.79, 127863], [1508893200000, 23.57, 23.69, 23.32, 23.35, 81565], [1508893260000, 23.6, 24.03, 23.55, 23.86, 56219], [1508893320000, 23.97, 24.24, 23.63, 23.77, 89107], [1508893380000, 24.05, 24.3, 23.96, 24.04, 94978], [1508893440000, 23.76, 24.04, 23.21, 23.37, 83000]]; } html, body, #container { width: 100%; height: 100%; margin: 0; padding: 0; } <script src="https://cdn.anychart.com/releases/v8/js/anychart-base.min.js"></script> <script src="https://cdn.anychart.com/releases/v8/js/anychart-stock.min.js"></script> <script src="https://cdn.anychart.com/releases/v8/js/anychart-ui.min.js"></script> <link href="https://cdn.anychart.com/releases/v8/fonts/css/anychart-font.css" rel="stylesheet"/> <link href="https://cdn.anychart.com/releases/v8/css/anychart-ui.min.css" rel="stylesheet"/> <div id="container"></div>
Web2py Rating Widget (5 of them and in the same line)
I have a new problem. I already done my widget but now i want 5 rating widget's for 5 categories in my database. I have this column in my database (named places.categ): places.categ a b c d a e .... I have 21 markers in my Google Maps and each one of them as a category. (a,b,c,d or e). How can i associate 5 rating widgets to those 21 markers by category? All i could do was this: db.define_table('product', Field('A', 'integer',requires=IS_IN_SET(range(1,6))), Field('B', 'integer',requires=IS_IN_SET(range(1,6))), Field('C', 'integer',requires=IS_IN_SET(range(1,6))), Field('D', 'integer',requires=IS_IN_SET(range(1,6))), Field('E', 'integer',requires=IS_IN_SET(range(1,6)))) I have this code in my models/db.py and this one in my controllers/default.py: from plugin_rating_widget import RatingWidget # Inject the widgets db.product.A.widget = RatingWidget() db.product.B.widget = RatingWidget() db.product.C.widget = RatingWidget() db.product.D.widget = RatingWidget() db.product.E.widget = RatingWidget() # form2 = SQLFORM.factory( # Field('Rating','integer',widget=SQLFORM.widgets.RatingWidget)) # if form2.process().accepted: # print form2.vars.search form2 = SQLFORM(db.product) if form2.accepts(request.vars, session): session.flash = 'submitted %s' % form2.vars redirect(URL('index')) I have 5 rating widget but they are not associated to my database and they are vertical (in 5 lines) and not in 1 line, like i wanted too. TIA. P.S.: I have the plugin rating widget uploaded.
I solved in another way. I get colors to each category with this code: var amarelo = new google.maps.MarkerImage( "http://labs.google.com/ridefinder/images/mm_20_yellow.png", new google.maps.Size(12, 20), new google.maps.Point(0, 0), new google.maps.Point(6, 20)); var vermelho = new google.maps.MarkerImage( "http://labs.google.com/ridefinder/images/mm_20_red.png", new google.maps.Size(12, 20), new google.maps.Point(0, 0), new google.maps.Point(6, 20)); var verde = new google.maps.MarkerImage( "http://labs.google.com/ridefinder/images/mm_20_green.png", new google.maps.Size(12, 20), new google.maps.Point(0, 0), new google.maps.Point(6, 20)); var azul = new google.maps.MarkerImage( "http://labs.google.com/ridefinder/images/mm_20_blue.png", new google.maps.Size(12, 20), new google.maps.Point(0, 0), new google.maps.Point(6, 20)); var branco = new google.maps.MarkerImage( "http://labs.google.com/ridefinder/images/mm_20_white.png", new google.maps.Size(12, 20), new google.maps.Point(0, 0), new google.maps.Point(6, 20)); var sombra = new google.maps.MarkerImage( "http://labs.google.com/ridefinder/images/mm_20_shadow.png", new google.maps.Size(22, 20), new google.maps.Point(0, 0), new google.maps.Point(6, 20)); I awarded each category in one of this colors (example): if (placescoordjs[i][4]== 'a') { marker = new google.maps.Marker({ position: new google.maps.LatLng(placescoordjs[i][1],placescoordjs[i][2]), icon: amarelo, shadow: sombra, map: map, title: placescoordjs[i][3] }); google.maps.event.addListener(marker, 'click', (function(marker, i) { return function() { infowindow.setContent(placescoordjs[i][0]); infowindow.open(map, marker); } })(marker, i)); } I have more 3 "else if" and the final else with the final color to my last category. Thanks anyway. ;)