I have signed a message using Solana's wallet adapter example:
import { useWallet } from '#solana/wallet-adapter-react';
import bs58 from 'bs58';
import React, { FC, useCallback } from 'react';
import { sign } from 'tweetnacl';
export const SignMessageButton: FC = () => {
const { publicKey, signMessage } = useWallet();
const onClick = useCallback(async () => {
try {
// `publicKey` will be null if the wallet isn't connected
if (!publicKey) throw new Error('Wallet not connected!');
// `signMessage` will be undefined if the wallet doesn't support it
if (!signMessage) throw new Error('Wallet does not support message signing!');
// Encode anything as bytes
const message = new TextEncoder().encode("hello");
// Sign the bytes using the wallet
const signature = await signMessage(message);
// Verify that the bytes were signed using the private key that matches the known public key
if (!sign.detached.verify(message, signature, publicKey.toBytes())) throw new Error('Invalid signature!');
alert(`Message signature: ${bs58.encode(signature)}`);
} catch (error: any) {
alert(`Signing failed: ${error?.message}`);
}
}, [publicKey, signMessage]);
return signMessage ? (<button onClick={onClick} disabled={!publicKey}>Sign Message</button>) : null;
};
Pubkey used: DKpHyR1WjWE23E3xizPUhefZKmpMrMXNBVfoxQ7WXCRR
Message signed: hello
Signature received: 3EWDdtU1w8pWkr6fg8faJvKn1wBZmNjgf5kUx4Pn5gw4HeBPYVDm7cTHNqpRVMami6yX36jdaeZacv9GXR19Jzye
But I am not being able to verify the signed message using Python 3.9 with PyNaCl and Solana-py. I have tried the following:
from nacl.signing import VerifyKey
from solana.publickey import PublicKey
import base58
pubkey = bytes(PublicKey("DKpHyR1WjWE23E3xizPUhefZKmpMrMXNBVfoxQ7WXCRR"))
msg = bytes("hello", 'utf8')
signed = bytes("3EWDdtU1w8pWkr6fg8faJvKn1wBZmNjgf5kUx4Pn5gw4HeBPYVDm7cTHNqpRVMami6yX36jdaeZacv9GXR19Jzye", 'utf8')
result = VerifyKey(
pubkey
).verify(
smessage=base58.b58decode(msg),
signature=base58.b58decode(signed)
)
But verification returns: nacl.exceptions.BadSignatureError: Signature was forged or corrupt.
Somebody knows what is wrong? Could it be an encoding problem? Seems like JS uses the following byte types:
pubkey: Uint8Array(32) [144, 188, 240, 167, 187, 75, 30, 17, 232, 175, 91, 222, 73, 68, 183, 218, 108, 56, 249, 64, 250, 61, 111, 168, 194, 233, 159, 2, 247, 5, 175, 124, buffer: ArrayBuffer(32), byteLength: 32, byteOffset: 0, length: 32]
message: Uint8Array(44) [57, 85, 65, 81, 76, 53, 81, 68, 67, 89, 122, 70, 112, 107, 119, 70, 88, 52, 88, 75, 53, 70, 119, 107, 66, 54, 67, 57, 116, 57, 116, 120, 65, 89, 52, 102, 102, 122, 69, 52, 114, 97, 113, 84, buffer: ArrayBuffer(44), byteLength: 44, byteOffset: 0, length: 44]
signed: Uint8Array(64) [111, 173, 219, 10, 169, 113, 163, 35, 30, 162, 250, 243, 191, 106, 195, 99, 238, 34, 49, 192, 19, 92, 111, 142, 57, 31, 158, 235, 65, 219, 146, 176, 174, 48, 30, 255, 160, 90, 174, 179, 219, 197, 252, 189, 150, 225, 160, 133, 163, 109, 159, 80, 56, 191, 11, 1, 91, 111, 196, 214, 231, 84, 11, 1, buffer: ArrayBuffer(64), byteLength: 64, byteOffset: 0, length: 64]
And in python:
pubkey: b'\xb7\x1e+\xef\xe19#y}\xa4L\xf2K\rK\xc3\xbby\x93\x1c\x00L\xe1<\x19g`-\x9d\xd5\xee\x94'
msg: b'Cn8eVZg'
signed: b'3EWDdtU1w8pWkr6fg8faJvKn1wBZmNjgf5kUx4Pn5gw4HeBPYVDm7cTHNqpRVMami6yX36jdaeZacv9GXR19Jzye'
Do I need to use some different encoding on Python?
Thanks for providing a concrete example on this, you're very close! The encoding is absolutely the issue here -- the pubkey is correctly encoded in Python as bytes. That first byte of \x90, encoded as two hex values, is 144 in JS, and you can check that in Python with: int('90', 16) = 144.
So to verify your key, you can instead use the base58 package https://github.com/keis/base58 and do:
from nacl.signing import VerifyKey
from solana.publickey import PublicKey
import base58
pubkey = bytes(PublicKey("DKpHyR1WjWE23E3xizPUhefZKmpMrMXNBVfoxQ7WXCRR"))
msg = bytes("hello", 'utf8')
signed = bytes("3EWDdtU1w8pWkr6fg8faJvKn1wBZmNjgf5kUx4Pn5gw4HeBPYVDm7cTHNqpRVMami6yX36jdaeZacv9GXR19Jzye", 'utf8')
result = VerifyKey(
pubkey
).verify(
smessage=msg,
signature=base58.b58decode(signed)
)
Note.- on smessage you don't need to use b58, because it was
encoded with new TextEncoder().encode("hello").
Second option: if you already have the UInt8Array from JS, you can do:
result = VerifyKey(bytes(PublicKey("HERE_THE_PUB_KEY"))
).verify(
smessage=bytes([byte1, byte2, byte3, ...])
signature=bytes([byte1, byte2, byte3, ...])
)
This is my test:
assert_noop!(
TemplateModule::commit_vote(
Origin::signed(5),
count - 1,
0,
"2-Votinghash".as_bytes().to_vec()
),
Error::<Test>::AlreadyCommitUsed
);
When I add another error its fails as:
thread 'tests::commit_vote' panicked at 'assertion failed: `(left == right)`
left: `Err(DispatchError::Module { index: 1, error: 7, message: Some("AlreadyCommitUsed") })`,
right: `Err(DispatchError::Module { index: 1, error: 4, message: Some("DepartmentNotAssociated") })`', pallets/template/src/tests.rs:106:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Where as when I add AlreadyCommitUsed as error, it gives following strange inequality:
thread 'tests::commit_vote' panicked at 'assertion failed: `(left == right)`
left: `[218, 23, 247, 200, 228, 182, 117, 227, 150, 32, 248, 47, 209, 182, 207, 246, 198, 19, 20, 74, 185, 125, 35, 94, 74, 161, 128, 199, 114, 155, 238, 228]`,
right: `[128, 69, 23, 167, 50, 250, 133, 59, 10, 41, 100, 95, 141, 187, 236, 154, 67, 174, 251, 17, 219, 45, 146, 141, 204, 77, 245, 38, 95, 131, 122, 48]`', pallets/template/src/tests.rs:106:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
This is my commit_vote function:
#[weight = 10_000 + T::DbWeight::get().reads_writes(3,3)]
pub fn commit_vote(origin, departmentid:u128, voting_cycle:u128, vote_commit:Vec<u8>) -> dispatch::DispatchResult {
let who = ensure_signed(origin.clone())?;
Self::check_citizen_associated_department(who.clone(), departmentid)?;
let status = VoteStatus::get((departmentid, voting_cycle, vote_commit.clone()));
match status {
Some(value) => {
if value == true {
Err(Error::<T>::AlreadyCommitUsed.into())
} else {
Err(Error::<T>::VoteRevealed.into())
}
}
None => {
Self::add_vote(departmentid, voting_cycle, vote_commit)?;
Ok(())
}
}
}
This is my helper function:
// Helper functions
impl<T: Config> Module<T> {
fn check_citizen_associated_department(
who: T::AccountId,
departmentid: u128,
) -> dispatch::DispatchResult {
let approved_peer_dep = PeerDepartments::<T>::get(&who);
match approved_peer_dep.binary_search(&departmentid) {
Ok(_) => {
Self::deposit_event(RawEvent::PeerDepartment(departmentid, who));
Ok(())
}
Err(_) => Err(Error::<T>::DepartmentNotAssociated.into()),
}
}
}
Yes, the error is because of the helper function, the error disappers when deposit_event of check_citizen_associated_department is removed. Not sure if its right way to write helper function.
This error:
thread 'tests::commit_vote' panicked at 'assertion failed: `(left == right)`
left: `[218, 23, 247, 200, 228, 182, 117, 227, 150, 32, 248, 47, 209, 182, 207, 246, 198, 19, 20, 74, 185, 125, 35, 94, 74, 161, 128, 199, 114, 155, 238, 228]`,
right: `[128, 69, 23, 167, 50, 250, 133, 59, 10, 41, 100, 95, 141, 187, 236, 154, 67, 174, 251, 17, 219, 45, 146, 141, 204, 77, 245, 38, 95, 131, 122, 48]`', pallets/template/src/tests.rs:106:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Is telling you that your extrinsic resulted in an error, but you also changed the state of the runtime. This is against the rules of how you can use Substrate.
This is the purpose of the assert_noop! macro:
https://crates.parity.io/frame_support/macro.assert_noop.html
There is a policy that all extrinsics must be "Check First, Write Last", as in, by the time you actually go about modifying the runtime state, there should be no way for an error to occur.
The problem seems to be that you emit an event in check_citizen_associated_department, which modifies the state, but then can error in match status.
You will need to fix your logic such that an event is only emitted when you know everything else will succeed.
I'm creating a pretty simple line graph and want the initial load to be a section of all available data, so am setting extent on the x axis:
This is how I am setting the extent:
axis: {
"x": {
"type": "timeseries",
"tick": {
"format": "%d/%m/%Y"
},
"label": {
"text": "X Label",
"position": "outer-center"
},
"padding": {
"left": 0
},
"extent": ["2017-10-01", "2017-10-05"]
},
"y": {
"label": {
"text": "Y Label",
"position": "outer-middle"
}
}
},
But it is ignored. The chart just shows the full extent of the data.
Is this the correct way to show a subset of the data when the chart is generated?
This is the full code and here's a fiddle (I tried a code snippet but didn't work)
const columnData = [
["x", "2017-10-01", "2017-10-02", "2017-10-03", "2017-10-04", "2017-10-05", "2017-10-06", "2017-10-07", "2017-10-08", "2017-10-09", "2017-10-10", "2017-10-11", "2017-10-12", "2017-10-13", "2017-10-14", "2017-10-15", "2017-10-16"],
["data0", -55, -50, 11, -18, 39, 65, -84, -15, 14, 81, -79, 67, -48, 38, 99, -60],
["data1", 28, 14, -99, -33, 55, 71, 58, 66, 7, -88, 99, -37, -7, 59, -13, -57],
["data2", 14, 6, -9, 25, 42, -93, -6, 67, -35, 88, 36, 45, 42, 78, 51, -88],
["data3", 31, -73, -69, 45, 55, 15, -48, 41, -64, -12, -6, 14, -69, 16, -65, -73],
["data4", 98, 60, 82, 80, -62, -47, 55, 87, -65, 37, 22, 30, 93, -69, -88, 33],
["data5", -98, 57, 71, -25, -40, 13, 72, -90, 71, -71, -21, -9, -90, 73, -94, 100]
];
const generateChart = function() {
const chart = c3.generate({
data: {
"x": "x",
"columns": columnData,
"type": "line"
},
axis: {
"x": {
"type": "timeseries",
"tick": {
"format": "%d/%m/%Y"
},
"label": {
"text": "X Label",
"position": "outer-center"
},
"padding": {
"left": 0
},
"extent": ["2017-10-01", "2017-10-05"]
},
"y": {
"label": {
"text": "Y Label",
"position": "outer-middle"
}
}
},
zoom: {
enabled: true
},
transition: {
duration: 100
},
legend: {
show: false
},
subchart: {
show: true
},
size: {
height: 500
},
grid: {
x: {
show: true
},
y: {
show: true
}
}
});
};
generateChart();
As of 11th May 2018 it seems this is a bug: https://github.com/c3js/c3/issues/2357
I switched to earlier versions (see below) of C3 and D3 and it works as it should.
I am now using C3 version 0.4.10 and D3 version 3.5.0
$("#spark-collector").kendoSparkline({
type: "line",
data: [
71, 70, 69, 68, 65, 60, 55, 55, 50, 52,
73, 72, 72, 71, 68, 63, 57, 58, 53, 55,
63, 59, 61, 64, 58, 53, 48, 48, 45, 45,
63, 64, 63, 67, 58, 56, 53, 59, 51, 54
],
valueAxis: {
min: 0,
max: 100
},
seriesColors: ["blue"],
tooltip: {
visible: true
}
});
How to change sparkline background color within Kendo UI?
I believe you can use PlotArea for that. Please refer to the documentation. You can set Background, border, margin, opacity and padding
https://www.telerik.com/kendo-angular-ui/components/charts/api/PlotArea/
You should use the property chartArea.background. Referring to your example:
$("#spark-collector").kendoSparkline({
type: "line",
charArea: {
background: "cyan"
},
data: [
71, 70, 69, 68, 65, 60, 55, 55, 50, 52,
73, 72, 72, 71, 68, 63, 57, 58, 53, 55,
63, 59, 61, 64, 58, 53, 48, 48, 45, 45,
63, 64, 63, 67, 58, 56, 53, 59, 51, 54
],
valueAxis: {
min: 0,
max: 100
},
seriesColors: ["blue"],
tooltip: {
visible: true
}
});
Check the documentation here
Following a code snippet...
$("#spark-collector").kendoSparkline({
type: "line",
chartArea: {
background: "cyan"
},
data: [
71, 70, 69, 68, 65, 60, 55, 55, 50, 52,
73, 72, 72, 71, 68, 63, 57, 58, 53, 55,
63, 59, 61, 64, 58, 53, 48, 48, 45, 45,
63, 64, 63, 67, 58, 56, 53, 59, 51, 54
],
valueAxis: {
min: 0,
max: 100
},
seriesColors: ["blue"],
tooltip: {
visible: true
}
});
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.221/styles/kendo.bootstrap-v4.min.css" />
<script src="https://kendo.cdn.telerik.com/2018.1.221/js/jquery.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2018.1.221/js/kendo.all.min.js"></script>
<div id="spark-collector"></div>
I am going to use sparkline in the" usage" column, just in the way that the two sparkline chart cover each other
There is a problem because when I click on the button Edite "sparkline" disappears.
Or click on "usage column" think that happens.
Why tooltip as bad as it can be displayed tooltip not regular.
Why sparkline "usage column" in all rows, there is only one row
jsfiddle code
$(document).ready(function () {
//var ds = new kendo.data.DataSource({
// transport: {
// read: {
// url: '/api/clientssnapshot',
// dataType: 'json',
// type: 'get',
// cache: false
// },
// },
// batch: true,
// pageSize: 10,
// schema: {
// model: {
// fields: {
// Mac: { editable: false, nullable: true },
// RadioName: { type: "string", validation: { required: true } },
// ApName: { type: "string", validation: { required: true, min: 1 } },
// RemoteIp: { type: "boolean" },
// TX: { type: "number", validation: { min: 0, required: true } },
// RX: { type: "number", validation: { min: 0, required: true } },
// Signal: { type: "number", validation: { min: 0, required: true } },
// Uptime: { type: "number", validation: { min: 0, required: true } },
// }
// }
// }
//});
$('.table').kendoGrid({
dataSource: {
data: [{
"Mac": "D4:CA:6D:28:D1:05",
"RadioName": "D4CA6D28D105",
"ApName": "Om11",
"ApIp": "10.20.0.100",
"TX": 48,
"RX": 54,
"Signal": -64,
"Uptime": 797452,
"InRate": 0,
"OutRate": 0,
"AccountingId": 759,
"AccountingName": "فرشاد صفایی زاده",
"RemoteIp": "188.121.123.56",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}, {
"Mac": "00:15:6D:BD:64:92",
"RadioName": "Behrooz Hoseyn",
"ApName": "Om11",
"ApIp": "10.20.0.100",
"TX": 48,
"RX": 18,
"Signal": -65,
"Uptime": 797446,
"InRate": 2,
"OutRate": 2,
"AccountingId": 750,
"AccountingName": "بهروز حسینی",
"RemoteIp": "188.121.123.48",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}, {
"Mac": "00:15:6D:1E:B3:6C",
"RadioName": "UBNT",
"ApName": "Om11",
"ApIp": "10.20.0.100",
"TX": 54,
"RX": 24,
"Signal": -65,
"Uptime": 310336,
"InRate": 0,
"OutRate": 0,
"AccountingId": 820,
"AccountingName": "******",
"RemoteIp": "10.10.15.129",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}, {
"Mac": "00:15:6D:1C:B1:89",
"RadioName": "Grous Tajhiz P",
"ApName": "Om11",
"ApIp": "10.20.0.100",
"TX": 48,
"RX": 6,
"Signal": -62,
"Uptime": 122116,
"InRate": 0,
"OutRate": 0,
"AccountingId": 595,
"AccountingName": "حمید شمس لواسانی",
"RemoteIp": "188.121.124.17",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}, {
"Mac": "00:27:22:3E:91:12",
"RadioName": "Anbar Aminzade",
"ApName": "Om1",
"ApIp": "10.20.0.101",
"TX": 36,
"RX": 36,
"Signal": -68,
"Uptime": 1131461,
"InRate": 4,
"OutRate": 4,
"AccountingId": 977,
"AccountingName": "انبار شهید امین زاده ",
"RemoteIp": "188.121.123.31",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}, {
"Mac": "00:15:6D:1A:59:D0",
"RadioName": "UBNT",
"ApName": "Om1",
"ApIp": "10.20.0.101",
"TX": 36,
"RX": 12,
"Signal": -73,
"Uptime": 734737,
"InRate": 2,
"OutRate": 2,
"AccountingId": 820,
"AccountingName": "******",
"RemoteIp": "10.10.15.76",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}, {
"Mac": "00:15:6D:E2:2D:13",
"RadioName": "UBNT",
"ApName": "Om1",
"ApIp": "10.20.0.101",
"TX": 54,
"RX": 36,
"Signal": -72,
"Uptime": 848,
"InRate": 0,
"OutRate": 0,
"AccountingId": 820,
"AccountingName": "******",
"RemoteIp": "10.10.15.67",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}, {
"Mac": "00:27:22:32:24:C9",
"RadioName": "UBNT",
"ApName": "Om7",
"ApIp": "10.20.0.100",
"TX": 36,
"RX": 24,
"Signal": -78,
"Uptime": 731588,
"InRate": 0,
"OutRate": 0,
"AccountingId": 820,
"AccountingName": "******",
"RemoteIp": "10.10.15.188",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}, {
"Mac": "00:15:6D:FE:BB:E2",
"RadioName": "ketabforooshie",
"ApName": "Om7",
"ApIp": "10.20.0.100",
"TX": 54,
"RX": 36,
"Signal": -72,
"Uptime": 240361,
"InRate": 0,
"OutRate": 0,
"AccountingId": 533,
"AccountingName": "قاسم رضاپور",
"RemoteIp": "188.121.124.214",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}, {
"Mac": "00:27:22:D2:86:56",
"RadioName": "UBNT",
"ApName": "Om7",
"ApIp": "10.20.0.100",
"TX": 48,
"RX": 12,
"Signal": -72,
"Uptime": 126430,
"InRate": 0,
"OutRate": 0,
"AccountingId": 1453,
"AccountingName": "حسن قربانی",
"RemoteIp": "188.121.123.154",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}, {
"Mac": "00:27:22:78:A3:19",
"RadioName": "UBNT",
"ApName": "Om7",
"ApIp": "10.20.0.100",
"TX": 54,
"RX": 54,
"Signal": -56,
"Uptime": 58617,
"InRate": 0,
"OutRate": 0,
"AccountingId": 820,
"AccountingName": "******",
"RemoteIp": "10.10.15.39",
"IsValidInScan": true,
"Comments": null,
"ApScanId": 26173,
"InRateHistory": "0, 0, 0, 0, 2, 0, 2, 16, 96, 16, 96, 16, 96, 113, 31, 113, 31, 113, 31, 0",
"OutRateHistory": "0, 5, 3, 5, 2, 5, 2, 35, 136, 35, 136, 35, 136, 164, 51, 164, 51, 164, 51, 4"
}
]
},
sortable: true,
groupable: true,
selectable: true,
navigatable: true,
height: 500,
scrollable: true,
pageable: true,
columns: [{
field: "Mac",
title: "Mac",
width: 170
}, {
field: "RadioName",
title: "Radio",
width: 150
}, {
field: "ApName",
title: "Ap",
width: 80,
template: '#=ApName#'
}, {
field: "RemoteIp",
title: "Remote IP",
width: 160,
template: '#=RemoteIp#'
}, {
field: "AccountingName",
title: "Name",
width: 130,
template: ' #= AccountingName # '
}, {
field: "TX",
title: "TX",
width: 44
}, {
field: "RX",
title: "RX",
width: 50
}, {
field: "Signal",
title: "Signal",
width: 50
}, {
field: "Uptime",
title: "Uptime",
width: 78
}, {
field: "Usage",
title: "Usage",
template: '<span id="sparkline"></span>'
}, {
command: ["edit"],
title: " "
}],
editable: "popup",
});
$(".ref").click(function () {
$(".table").data("kendoGrid").dataSource.read();
});
$("#sparkline").kendoSparkline({
type: "area",
series: [{
name: "World",
data: [15.7, 16.7, 20, 23.5, 26.6, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5, 3.5],
}, {
name: 'New York',
data: [0.7, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5],
}],
categoryAxis: {
categories: [2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015]
}
});
<div class="span6 box gradient main_stting">
<div class="dataTables_filter" id="txtSearch">
<label>Search:
<input type="text" aria-controls="DataTables_Table_0">
</label>
</div>
<div class="title">
<button class="btn ref" type="submit">Refresh</button>
<h3></h3>
</div>
<div class="content">
<div class="table"></div>
</div>
thank you
After edit, the HTML elements are destroyed and recreated when the Grid updates. You will need to recreate your sparklines. It is basically the same as this issue.