How to get quill-image-resize to work when quill 'value' is passed in from parent component as a prop - javascript

I am currently using React Quill to create a template creator/editor, and used the Quill-Image-Resize-Module for resizing of images. It was working up until the point that I needed to hoist [HTML, setHTML] to the parent component - now they are passed in as props and everything works apart from image resizing.
import React from "react";
import ReactQuill, { Quill }from "react-quill";
import ImageResize from 'quill-image-resize-module-react';
import "react-quill/dist/quill.snow.css";
const Block = Quill.import("blots/block");
Block.tagName = "DIV";
Quill.register(Block, true);
Quill.register('modules/imageResize', ImageResize);
const keyboardBindings = {
linebreak: {
key: 13,
handler: function (range, _context) {
this.quill.clipboard.dangerouslyPasteHTML(
range.index,
"<p><br/></p>"
);
}
}
};
const modules = {
toolbar: [
["bold", "italic", "underline", "header", "image", "code-block"],
[{ list: "ordered" },{ list: "bullet" }],
[{ header: [1, 2, false] }]
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'color': [] }, { 'background': [] }],
],
keyboard: {
bindings: keyboardBindings
},
imageResize: {
parchment: Quill.import('parchment'),
modules: ['Resize', 'DisplaySize', 'Toolbar']
}
};
const formats = [
"bold", "italic", "underline", "list", "bullet", "header", "image", "code-block"
];
function Editor({HTML, setHTML, setText}) {
const handleChange = (content, _delta, _source, editor) => {
const html = content ? content.replace(/style\s*?=\s*?([‘"])[\s\S]*?\1/, "") : "";
const text = editor.getText(html);
setHTML && setHTML(html);
setText && setText(text);
}
return (
<ReactQuill
className="ql-editor"
style={{ height: "600px", overflow: "auto" }}
theme="snow"
modules={modules}
formats={formats}
value={HTML}
onChange={handleChange}
/>
);
}
export default Editor;
So my question is can anybody help me to understand why and the best way to resolve/workaround?

Related

ReactNative Fusionchart license configuration not working

I try to configure the license of Fusionchart in ReactNative as in this URL https://www.npmjs.com/package/react-native-fusioncharts#license-configuration.
But still, it shows the watermark which should not be visible. Is there anything I missed?
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View, Platform } from 'react-native';
import ReactNativeFusionCharts from 'react-native-fusioncharts';
global.licenseConfig = {
key: "license-key",
creditLabel: false // true/false to show/hide watermark respectively
};
export default class App extends Component {
constructor(props) {
super(props);
//STEP 2 - Chart Data
const chartData = [
{ label: 'Venezuela', value: '250' },
{ label: 'Saudi', value: '260' },
{ label: 'Canada', value: '180' },
{ label: 'Iran', value: '140' },
{ label: 'Russia', value: '115' },
{ label: 'UAE', value: '100' },
{ label: 'US', value: '30' },
{ label: 'China', value: '30' },
];
//STEP 3 - Chart Configurations
const chartConfig = {
type: 'column2d',
width: 400,
height: 400,
dataFormat: 'json',
dataSource: {
chart: {
caption: 'Countries With Most Oil Reserves [2017-18]',
subCaption: 'In MMbbl = One Million barrels',
xAxisName: 'Country',
yAxisName: 'Reserves (MMbbl)',
numberSuffix: 'K',
theme: 'fusion',
exportEnabled: 1, // to enable the export chart functionality
},
data: chartData,
},
};
const events = {
// Add your events method here:
// Event name should be in small letters.
dataPlotClick: (ev, props) => {
console.log('dataPlotClick');
},
dataLabelClick: (ev, props) => {
console.log('dataLabelClick');
},
};
this.state = {
chartConfig,
events
};
}
render() {
return (
<View style={styles.container}>
<Text style={styles.heading}>FusionCharts Integration with React Native</Text>
<View style={styles.chartContainer}>
<ReactNativeFusionCharts chartConfig={this.state.chartConfig} events={this.state.events} />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 50,
height: 500,
backgroundColor: 'white'
},
heading: {
fontSize: 20,
textAlign: 'center',
marginBottom: 10,
},
chartContainer: {
borderColor: 'red',
borderWidth: 1,
height: 500,
},
});
// skip this line if using Create React Native App
AppRegistry.registerComponent('ReactNativeFusionCharts', () => App);
I also add the below code in the root component but not worked.
global.licenseConfig = {
key: "license-key",
creditLabel: false // true/false to show/hide watermark respectively
};
Answering my own question. Hope this will be helpful to someone.
Issue is latest react-native-fusionchart 5.0.0 is not updated with fusionchart 3.17.0. You may need to manually copy the fusionchart content to react-native-fusionchart.
Copy the node_module/fusionchart content into node_modules/react-native-fusioncharts/src/modules/fusionchart folder and run below script.
find fusioncharts -name "*.js" -exec sh -c 'mv "$0" "${0%.js}.fcscript"' {} \;
Then the watermark vanishes as expected. These steps are configured in the gulp script but somehow it seems to be not working.
Hope this issue will be fixed soon.

react native : How to display the table inside the accordion In my example?

In my example I present an accordion separately and a table separately and I wanted to know how I present the table within the accordion.
this is the accordion that i want put inside it the table as in the example below :
import React, { Component } from "react";
import { Container, Header, Content, Accordion } from "native-base";
const dataArray = [
{ title: "First Element", content: "**I WANT PUT HERE THE TABLE**" },
{ title: "Second Element", content: "BO" },
{ title: "Third Element", content: "MO" }
];
export default class AccordionHeaderContentStyleExample extends Component {
render() {
return (
<Container>
<Header />
<Content padder>
<Accordion
dataArray={dataArray}
headerStyle={{ backgroundColor: "#b7daf8" }}
contentStyle={{ backgroundColor: "#ddecf8" }}
/>
</Content>
</Container>
);
}
}
this is the table that i want put inside the "content" of the "First Element" accordion above :
import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';
import { Table, Row, Rows } from 'react-native-table-component';
export default class ExampleOne extends Component {
constructor(props) {
super(props);
this.state = {
tableHead: ['Head', 'Head2', 'Head3', 'Head4'],
tableData: [
['1', '2', '3', '4'],
['a', 'b', 'c', 'd'],
['1', '2', '3', '456\n789'],
['a', 'b', 'c', 'd']
]
}
}
render() {
const state = this.state;
return (
<View style={styles.container}>
<Table borderStyle={{borderWidth: 2, borderColor: '#c8e1ff'}}>
<Row data={state.tableHead} style={styles.head} textStyle={styles.text}/>
<Rows data={state.tableData} textStyle={styles.text}/>
</Table>
</View>
)
}
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 16, paddingTop: 30, backgroundColor: '#fff' },
head: { height: 40, backgroundColor: '#f1f8ff' },
text: { margin: 6 }
});
Try this might help
import ExampleOne from "../components/ExampleOne";
// ExampleOne is the component that should be rendered inside content of dataArray
renderExampleOne = () => {
return <ExampleOne />;
};
const dataArray = [
{ title: "First Element", content: this.renderExampleOne() },
{ title: "Second Element", content: "BO" },
{ title: "Third Element", content: "MO" }
];
renderContent(item: ArrayContent) {
return item.content;
}
<Accordion
dataArray={dataArray}
headerStyle={{ backgroundColor: "#b7daf8" }}
contentStyle={{ backgroundColor: "#ddecf8" }}
renderContent={this.renderContent}
/>

Printing a list by clicking chart Chart js + react

Hi i'm having troubles printing in a alert (by clicking one of the portions), a list of users for a specific answer in chart.js + react here's my chart component
Piechart.js
import React,{ Component } from 'react';
import {Chart} from 'react-chartjs-2';
class Piechart extends Component {
constructor(props){
super(props)
this.chartReference = React.createRef();
this.state = {
data:[]
};
}
async componentDidMount(){
const url = "https://api-tesis-marco.herokuapp.com/api/v1/questiondata/"+this.props.title;
const data = await fetch(url)
.then(response => response.json());
this.setState({data:data});
this.myChart = new Chart(this.chartReference.current,{
type: 'pie',
data:{
labels: this.state.data.map(d=>d.Respuesta),
datasets: [{
data: this.state.data.map(d=>d.porcentaje),
backgroundColor: this.props.colors
}],
},
options: {
title: {
display: true,
text: this.props.title,
fontSize: 20,
fontStyle: 'bold'
},
legend: {
position:'right'
},
onClick: clicked
}
});
function clicked(evt){
var element = this.getElementAtEvent(evt);
if(element[0]){
alert();
}
}
}
render(){
return(
<canvas ref={this.chartReference} />
)
}
}
export default Piechart;
//i having troubles passing the lists data of my request
function clicked(evt){
var element = this.getElementAtEvent(evt);
if(element[0]){
//i don't know what to do here
alert();
}
}
Here is the json response of my request:
Data:
[
{
"Respuesta": "A",
"porcentaje": 7,
"quien": [
"1",
"visita1"
]
},
{
"Respuesta": "B",
"porcentaje": 3,
"quien": [
"coco"
]
},
{
"Respuesta": "C",
"porcentaje": 3,
"quien": [
"Dani3l"
]
},
{
"Respuesta": "D",
"porcentaje": 10,
"quien": [
"Gabi",
"test",
"visita prueba"
]
},
{
"Respuesta": "No ha respondido",
"porcentaje": 76,
"quien": [
"9punto5",
"Colita de algodón",
"KarmenQueen",
"Prueba",
"ancova",
"cehum2",
"chuky",
"dev",
"felipe",
"gabs",
"icom2019",
"invunche",
"john",
"laura",
"marian",
"marti",
"pablazozka",
"prueba",
"test1",
"titicaco",
"visita 1",
"visita test"
]
}
]
in my clicked function how can i pass the "quien" lists for the specific portion of my pie chart?, so in the alert i can print the list of that portion , i'm using this as guide https://jsfiddle.net/u1szh96g/208/ but is difficult for me adapt this to react
well after some mixed tutorials and guides, i came with the solution
Piechart.js:
import React,{ Component } from 'react';
import {Chart} from 'react-chartjs-2';
class Piechart extends Component {
constructor(props){
super(props)
this.chartReference = React.createRef();
this.state = {
data:[]
};
}
async componentDidMount(){
const url = "https://api-tesis-marco.herokuapp.com/api/v1/questiondata/"+this.props.title;
const data = await fetch(url)
.then(response => response.json());
this.setState({data:data});
var datasets = [{data: this.state.data.map(d=>d.Count),
backgroundColor: this.props.colors
},
{
data: this.state.data.map(d=>d.Percent)
},
{
data: this.state.data.map(d=>d.Who)}]
this.myChart = new Chart(this.chartReference.current,{
type: 'pie',
data:{
labels: this.state.data.map(d=>d.Answer),
datasets: [{
data: datasets[0].data,
backgroundColor: datasets[0].backgroundColor
}]
},
options: {
title: {
display: true,
text: this.props.title,
fontSize: 20,
fontStyle: 'bold'
},
legend: {
position:'right'
},
tooltips:{
callbacks: {
title: function(tooltipItem, data) {
return 'Respuesta:'+data['labels'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
return 'Total:'+data['datasets'][0]['data'][tooltipItem['index']];
},
afterLabel: function(tooltipItem) {
var dataset = datasets[1];
var total = dataset['data'][tooltipItem['index']]
return '(' + total+ '%)';
}
},
backgroundColor: '#FFF',
titleFontSize: 16,
titleFontColor: '#0066ff',
bodyFontColor: '#000',
bodyFontSize: 14,
displayColors: false
},
onClick: clicked
}
});
function clicked(evt){
var element = this.getElementAtEvent(evt);
if(element[0]){
var idx = element[0]['_index'];
var who = datasets[2].data[idx];
alert(who);
}
}
}
render(){
return(
<canvas ref={this.chartReference} />
)
}
}
export default Piechart;
as you can see i only set an datasets array outside
var datasets = [{
data: this.state.data.map(d=>d.Count),
backgroundColor: this.props.colors
},
{
data: this.state.data.map(d=>d.Percent)
},
{
data: this.state.data.map(d=>d.Who)}]
this contains all the datasets of the request, then in the chart instance i only pass the dataset i want to plot, then for my question, in the clicked function only call the element of the array wich contains the list of users for the specific answer
Cliked function:
function clicked(evt){
var element = this.getElementAtEvent(evt);
if(element[0]){
var idx = element[0]['_index'];
var who = datasets[2].data[idx];
alert(who);
}
}
i made a custom tooltip as well, but i have an issue with this(with the default tooltip is the same) because i use this component to plot 4 piecharts but when i hover the mouse only 2 of the 4 charts show me the tooltip, the 2 chart who shows the tooltip are random (when refresh localhost pick randomly 2 of the 4 charts), and i don't know what is happend or how to fix this, i hope this is usefull to someone

How to send an array of object as a prop?

I have a state which is an object containing an array and that array contains an object which looks something like this
[{"tone":"negative","value":0},{"tone":"neutral","value":91},{"tone":"positive","value":9}].
So I want to plot a bar chart using only the values from this array of objects. I want to send these values to another component which can be used to plot bar charts dynamically. But I'm not sure how to do it. can someone please show how to send the values to the barchart component and use them in the barchart as well?
This is the code
state={
analysis: {
tonal: [],
anxiety: []
}
}
Analysis = async () => {
//some api call
const {
...tonalAnalysis
} = result.scores;
const tonalArray = Object.entries(tonalAnalysis).reduce(
(carry, [tone, value]) => [
...carry,
{ tone: tone.toLowerCase(), value: parseInt(value) }
],
[]
);
this.setState({
analysis: { ...this.state.analysis, tonal: tonalArray }
});
console.log("Tonal array" + JSON.stringify(this.state.analysis.tonal)); //console logs `[{"tone":"negative","value":0},{"tone":"neutral","value":91},{"tone":"positive","value":9}]`
};
render(){
return {
<BarCharts/> // confused how to send the values as props here
}
the bar chart component where I will use
import React from "react";
import { Bar } from "react-chartjs-2";
import "./App.css";
class BarCharts extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {
labels: [
negative,
neutral,
positive
],
datasets: [
{
label: "Value plotting",
backgroundColor: "rgba(255,99,132,0.2)",
borderColor: "rgba(255,99,132,1)",
borderWidth: 1,
hoverBackgroundColor: "rgba(255,99,132,0.4)",
hoverBorderColor: "rgba(255,99,132,1)",
data: [65, 59, 80, 81, 56, 55, 40] //want to use the values here dynamically. Don't want these static values
}
]
}
};
}
render() {
const options = {
responsive: true,
legend: {
display: false
},
type: "bar"
};
return (
<Bar
data={this.state.data}
width={null}
height={null}
options={options}
/>
);
}
}
export default BarCharts;
You can create a HighChart wrapper component that can be used for any Highchart graphs.
Note:- every time the data set changes you need to destroy and re-render the graph again in order to make the graph reflect changes.
// #flow
import * as React from "react";
import merge from "lodash/merge";
import Highcharts from "highcharts";
import isEqual from "lodash/isEqual";
export type Props = {
config?: Object,
data: Array<any>,
onRendered?: () => void
};
class HighchartWrapper extends React.PureComponent<Props> {
container: ?HTMLElement;
chart: any;
static defaultProps = {
config: {},
onRendered: () => {}
};
componentDidMount() {
this.drawChart(this.props);
}
componentWillReceiveProps(nextProps: Props) {
const data= [...this.props.data];
if (!isEqual(nextProps.config, this.props.config) || !isEqual(nextProps.data, data)) {
this.destroyChart();
this.drawChart(nextProps);
}
}
destroyChart() {
if (this.chart) {
this.chart.destroy();
}
}
componentWillUnmount() {
this.destroyChart();
}
drawChart = (props: Props) => {
const { config: configProp, data, onRendered } = props;
if (this.container) {
let config = merge({}, configProp);
this.chart = new Highcharts.chart(this.container, { ...{ ...config, ...{ series: [...data] } } }, onRendered);
}
};
render() {
return <div ref={ref => (this.container = ref)} />;
}
}
export default HighchartWrapper;
In order use it for BarChart just pass the appropriate bar chart config.
<HighchartWrapper config={{
chart: {
type: "bar"
}
}}
data={[]}
>
Edit
import React from "react";
import BarChart from "./BarChart";
export default function App() {
return (
<div style={{ width: 400, height: 840 }}>
<BarChart
config={{
chart: {
height: 840,
type: "bar"
},
xAxis: {
categories: ["Positive", "Neutral", "Negative" ],
title: {
text: null
}
},
yAxis: {
min: 0,
title: {
text: "Population (millions)",
align: "high"
},
labels: {
overflow: "justify"
}
}
}}
data={[
{
name: "Series Name",
data: [90, 9, 10]
}
]}
/>
</div>
);
}
Just add your desired props in at component declaration :
<BarCharts data={this.state.analysis}/>
And on your BarChart Component you will need to just extract the values from your arrays, this just in case you need the same structure:
...
this.state = {
data: {
labels: [
negative,
neutral,
positive
],
datasets: [
{
label: "Value plotting",
backgroundColor: "rgba(255,99,132,0.2)",
borderColor: "rgba(255,99,132,1)",
borderWidth: 1,
hoverBackgroundColor: "rgba(255,99,132,0.4)",
hoverBorderColor: "rgba(255,99,132,1)",
data: extractValues(this.props.data)
}
]
}
...
//This method can be reused in a hook or in a lifecycle method to keep data updated.
const extractValues = (data) => {
return data.map( d => d.value);
}
You can map the array so your code would be:
state={
analysis: {
tonal: [],
anxiety: []
}
}
Analysis = async () => {
//some api call
const {
...tonalAnalysis
} = result.scores;
const tonalArray = Object.entries(tonalAnalysis).reduce(
(carry, [tone, value]) => [
...carry,
{ tone: tone.toLowerCase(), value: parseInt(value) }
],
[]
);
this.setState({
analysis: { ...this.state.analysis, tonal: tonalArray }
});
console.log("Tonal array" + JSON.stringify(this.state.analysis.tonal)); //console logs `[{"tone":"negative","value":0},{"tone":"neutral","value":91},{"tone":"positive","value":9}]`
};
render(){
return {
<BarCharts values={this.state.analysis.tonal.map((entry) => entry.value)}/> // confused how to send the values as props here
}
And your barchart would be:
import React from "react";
import { Bar } from "react-chartjs-2";
import "./App.css";
class BarCharts extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {
labels: [
negative,
neutral,
positive
],
datasets: [
{
label: "Value plotting",
backgroundColor: "rgba(255,99,132,0.2)",
borderColor: "rgba(255,99,132,1)",
borderWidth: 1,
hoverBackgroundColor: "rgba(255,99,132,0.4)",
hoverBorderColor: "rgba(255,99,132,1)",
data: props.values //want to use the values here dynamically. Don't want these static values
}
]
}
};
}
render() {
const options = {
responsive: true,
legend: {
display: false
},
type: "bar"
};
return (
<Bar
data={this.state.data}
width={null}
height={null}
options={options}
/>
);
}
}
export default BarCharts;

react-native can't open expo project

I am trying to run an expo project Collapsible Header with TabView it works fine in this link.
But when I copy and paste the code to my own expo project, it gives me an error.
Invariant Violation: Element type is invalid: expected a string or a class/function. Check the render method of App
The only thing I changed is class TabView to class App but it is giving me this error.
Also, if I want to build a native code project not expo. How would I run this code? because there is import {Constants } from expo this wouldn't work in react-native run-ios
import * as React from 'react';
import {
View,
StyleSheet,
Dimensions,
ImageBackground,
Animated,
Text
} from 'react-native';
import { Constants } from 'expo';
import { TabViewAnimated, TabBar } from 'react-native-tab-view'; // Version can be specified in package.json
import ContactsList from './components/ContactsList';
const initialLayout = {
height: 0,
width: Dimensions.get('window').width,
};
const HEADER_HEIGHT = 240;
const COLLAPSED_HEIGHT = 52 + Constants.statusBarHeight;
const SCROLLABLE_HEIGHT = HEADER_HEIGHT - COLLAPSED_HEIGHT;
export default class TabView extends React.Component {
constructor(props: Props) {
super(props);
this.state = {
index: 0,
routes: [
{ key: '1', title: 'First' },
{ key: '2', title: 'Second' },
{ key: '3', title: 'Third' },
],
scroll: new Animated.Value(0),
};
}
_handleIndexChange = index => {
this.setState({ index });
};
_renderHeader = props => {
const translateY = this.state.scroll.interpolate({
inputRange: [0, SCROLLABLE_HEIGHT],
outputRange: [0, -SCROLLABLE_HEIGHT],
extrapolate: 'clamp',
});
return (
<Animated.View style={[styles.header, { transform: [{ translateY }] }]}>
<ImageBackground
source={{ uri: 'https://picsum.photos/900' }}
style={styles.cover}>
<View style={styles.overlay} />
<TabBar {...props} style={styles.tabbar} />
</ImageBackground>
</Animated.View>
);
};
_renderScene = () => {
return (
<ContactsList
scrollEventThrottle={1}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.scroll } } }],
{ useNativeDriver: true }
)}
contentContainerStyle={{ paddingTop: HEADER_HEIGHT }}
/>
);
};
render() {
return (
<TabViewAnimated
style={styles.container}
navigationState={this.state}
renderScene={this._renderScene}
renderHeader={this._renderHeader}
onIndexChange={this._handleIndexChange}
initialLayout={initialLayout}
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
overlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, .32)',
},
cover: {
height: HEADER_HEIGHT,
},
header: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
zIndex: 1,
},
tabbar: {
backgroundColor: 'rgba(0, 0, 0, .32)',
elevation: 0,
shadowOpacity: 0,
},
});
I got it worked! I had to replace TabViewAnimated to TabView.

Categories

Resources