How to apply SVG texture on OBJ file in Three.js - svg

I'm using Threejs for a project of mine, i render an Object file using OBJ loader and it displays the object on the screen. But I don't know how to map a SVG image to that object how to apply texture on that object file.
please help me this is my current code.
I'm new to this platform and don't know much about THREE.js i've seen some examples but it didn't worked out for me.
One person on my recent post told me how to apply material on the object but it didn't worked for me.
When i apply material i got this error.
ERROR TypeError: Cannot set property 'map' of undefined
Here is my complete code file.
import { Component, AfterViewInit, ViewChild, Input, ElementRef } from '#angular/core';
import * as THREE from 'three';
import { OrbitControls } from '#avatsaev/three-orbitcontrols-ts';
import {OBJLoader} from 'three-obj-mtl-loader';
import { TextureLoader } from 'three';
#Component({
selector: 'app-scene',
templateUrl: './scene.component.html',
styleUrls: ['./scene.component.css']
})
export class SceneComponent implements AfterViewInit {
#Input() name: string;
#ViewChild('canvas', {static:true}) canvasRef: ElementRef;
renderer = new THREE.WebGLRenderer;
scene = null;
camera = null;
controls = null;
mesh = null;
light = null;
loader;
svgLoader;
private calculateAspectRatio(): number {
const height = this.canvas.clientHeight;
if (height === 0) {
return 0;
}
return this.canvas.clientWidth / this.canvas.clientHeight;
}
private get canvas(): HTMLCanvasElement {
return this.canvasRef.nativeElement;
}
constructor() {
// this.loader = new OBJLoader();
this.scene = new THREE.Scene();
this.loader = new OBJLoader();
this.camera = new THREE.PerspectiveCamera(15, window.innerWidth / window.innerHeight, 0.1, 1000)
}
ngAfterViewInit() {
this.configScene();
this.configCamera();
this.configRenderer();
this.configControls();
this.createLight();
this.createMesh();
this.animate();
}
configScene() {
// this.scene.background = new THREE.Color( 0xdddddd );
}
configCamera() {
this.camera.aspect = this.calculateAspectRatio();
this.camera.updateProjectionMatrix();
this.camera.position.set( 0, 0, 3 );
this.camera.lookAt( this.scene.position );
}
configRenderer() {
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true,
alpha: true
});
this.renderer.setPixelRatio(devicePixelRatio);
// setClearColor for transparent background
// i.e. scene or canvas background shows through
this.renderer.setClearColor( 0x000000, 0 );
this.renderer.setSize((window.innerWidth/2), (window.innerHeight/2));
window.addEventListener('resize', ()=>{
this.renderer.setSize((window.innerWidth/2), (window.innerHeight)/2);
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
})
console.log('clientWidth', this.canvas.clientWidth);
console.log('clientHeight', this.canvas.clientHeight);
}
configControls() {
this.controls = new OrbitControls(this.camera);
this.controls.autoRotate = false;
this.controls.enableZoom = false;
// this.controls.maxDistance = 5;
// this.controls.minDistance = 10;
this.controls.enablePan = false;
this.controls.update();
}
createLight() {
this.light = new THREE.PointLight( 0xffffff );
this.light.position.set( -10, 10, 10 );
this.scene.add( this.light );
}
createMesh() {
const url ='../../../../assets/abc.svg';
this.loader.load('../../../../assets/nonunified.obj', (object)=>{
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.geometry.center();
}
} );
object.material.map = new TextureLoader().load(url)
this.scene.add(object)
},
// called when loading is in progresses
function (xhr) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
// called when loading has errors
function ( error ) {
console.log( 'An error happened' );
}
)}
animate() {
window.requestAnimationFrame(() => this.animate());
this.controls.update();
this.renderer.render(this.scene, this.camera);
}
}

You have not created a material. If you do console.log(object.material); it will show undefined. You first need to create a material. Please check the threejs doc for different materials that can be used. For this example I am using MeshPhongMaterial. So your createMesh function will look like this.
createMesh() {
const url = '../../../../assets/abc.svg';
this.loader.load('../../../../assets/nonunified.obj', (object) => {
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.geometry.center();
}
});
const material = new THREE.MeshPhongMaterial({
map: new TextureLoader().load(url)
});
object.material = material;
this.scene.add(object)
},
// called when loading is in progresses
function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
// called when loading has errors
function (error) {
console.log('An error happened');
}
)
}
This should work.

Related

Custom Card rendering when no longer presented?

I'm new to building custom cards for HASS so this might be obvious.
I have a basic clock card and I have put a console message on the render method - it seems to be writing to the log even when the card is no longer being presented? (i.e. you've moved to another lovelace view).
I'm using a setTimeout to trigger a property change - am I meant to stop the timeout at some point of the lifecycle, or is there some teardown in the lifecycle, etc?
Here's my code:
/* eslint-disable #typescript-eslint/no-explicit-any */
import {
LitElement,
html,
customElement,
property,
CSSResult,
TemplateResult,
css,
PropertyValues,
internalProperty,
} from 'lit-element';
import {
HomeAssistant,
hasConfigOrEntityChanged,
hasAction,
ActionHandlerEvent,
handleAction,
LovelaceCardEditor,
getLovelace,
LovelaceCard,
} from 'custom-card-helpers'; // This is a community maintained npm module with common helper functions/types
import { hass, provideHass } from "card-tools/src/hass";
import './editor';
import type { BoilerplateCardConfig } from './types';
import { actionHandler } from './action-handler-directive';
import { CARD_VERSION } from './const';
import { localize } from './localize/localize';
/* eslint no-console: 0 */
console.info(
`%c BOILERPLATE-CARD \n%c ${localize('common.version')} ${CARD_VERSION} `,
'color: orange; font-weight: bold; background: black',
'color: white; font-weight: bold; background: dimgray',
);
// This puts your card into the UI card picker dialog
(window as any).customCards = (window as any).customCards || [];
(window as any).customCards.push({
type: 'boilerplate-card',
name: 'Boilerplate Card',
description: 'A template custom card for you to create something awesome',
});
// TODO Name your custom element
#customElement('boilerplate-card')
export class BoilerplateCard extends LitElement {
CUSTOM_TYPE_PREFIX = "custom:";
constructor() {
super();
this.date = new Date();
setInterval(() => {
this.date = new Date();
}, 1000);
}
public static async getConfigElement(): Promise<LovelaceCardEditor> {
return document.createElement('boilerplate-card-editor');
}
public static getStubConfig(): object {
return {};
}
// TODO Add any properities that should cause your element to re-render here
// https://lit-element.polymer-project.org/guide/properties
#property({ attribute: false }) public hass!: HomeAssistant;
#internalProperty() private date: Date;
#internalProperty() private config!: BoilerplateCardConfig;
// https://lit-element.polymer-project.org/guide/properties#accessors-custom
public setConfig(config: BoilerplateCardConfig): void {
// TODO Check for required fields and that they are of the proper format
if (!config) {
throw new Error(localize('common.invalid_configuration'));
}
if (config.test_gui) {
getLovelace().setEditMode(true);
}
this.config = {
name: 'Boilerplate',
...config,
};
}
// https://lit-element.polymer-project.org/guide/lifecycle#shouldupdate
protected shouldUpdate(changedProps: PropertyValues): boolean {
return hasConfigOrEntityChanged(this, changedProps, true);
}
// https://lit-element.polymer-project.org/guide/templates
protected render(): TemplateResult | void {
const timeFormatter: Intl.DateTimeFormatOptions = {
year: undefined,
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
}
console.info("Draw")
return html`
<ha-card
.header=${this.config.name}
.actionHandler=${actionHandler({
hasHold: hasAction(this.config.hold_action),
hasDoubleClick: hasAction(this.config.double_tap_action),
})}
tabindex="0"
.label=${`Boilerplate: ${this.config.entity || 'No Entity Defined'}`}
>
<h1>${new Intl.DateTimeFormat(undefined, timeFormatter).format(this.date)}</h1>
${this.config.cards.map((card) => {
let tag = card.type;
if (tag.startsWith(this.CUSTOM_TYPE_PREFIX)) {
tag = tag.substr(this.CUSTOM_TYPE_PREFIX.length);
} else {
tag = `hui-${tag}-card`;
}
const cardElement = document.createElement(tag) as LovelaceCard;
cardElement.setConfig(card);
cardElement.hass = hass();
return cardElement
})}
</ha-card>
`;
}
// https://lit-element.polymer-project.org/guide/styles
static get styles(): CSSResult {
return css``;
}
}
Use connectedCallback and disconnectedCallback to start and stop your timer:
#customElement('boilerplate-card')
export class BoilerplateCard extends LitElement {
connectedCallback() {
super.connectedCallback();
this.date = new Date();
this.interval = setInterval(() => {
this.date = new Date();
}, 1000);
}
disconnectedCallback() {
super.disconnectedCallback();
clearInterval(this.interval);
}
...
}

vuetify + jest lists error messages although test is green

As a vue newbie I wrote a test for a component. The test is green. However, when using vuetify in the component under test (v-layout, v-flex) error messages are listed in the console output. They disappear when removing vuetify in the component (v-layout, v-flex). How can I use vuetify and still avoid those messages?
The component TestForm
<script>
import "#/assets/Styles";
import {cloneDeep} from "lodash";
import VForm from "vuetify/es5/components/VForm";
import VBtn from "vuetify/es5/components/VBtn";
import {VContainer, VContent, VFlex, VLayout, VSpacer} from "vuetify/es5/components/VGrid";
import VTextField from "vuetify/es5/components/VTextField";
import {VCard, VCardText, VCardTitle} from "vuetify/es5/components/VCard";
import TestModelData from "#/api/model/example/TestModelData";
import TestData from "#/api/model/example/TestData";
import TestStatus from "#/api/model/example/TestStatus";
import TestStatusSelect from "#/components/common/TestStatusSelect";
export default {
components: {
VBtn,
VForm,
TestModelData, TestData, TestStatus, TestStatusSelect,
VCard, VCardTitle, VCardText,
VContainer, VContent, VLayout, VFlex, VSpacer,
VTextField
},
props: {
testModelData: TestModelData
},
data() {
return {
currentTestModelData: this.testModelData,
testData: this.testData ? cloneDeep(this.testData) : new TestData()
};
},
watch: {
"testModelData.testdata": function (val) {
console.log("Testdata has changed;", val);
if (val) {
this.testData = cloneDeep(val);
} else {
this.testData = new TestData();
}
}
},
computed: {
readOnly: function () {
if (this.testData.testStatus.id !== TestStatus.FIRST.id) {
return true;
} else {
return false;
}
}
},
methods: {
onFormChange(event) {
console.log("Changed: ", event);
this.$store.dispatch({
type: "testModelData/setTestData",
testData: this.testData
});
}
}
};
</script>
<template>
<v-form ref="form">
<v-layout wrap>
<v-flex xs12 lg6>
<TestStatusSelect
ref="testDataSelect"
v-model="testData.testStatus"
#change="onFormChange($event)"/>
</v-flex>
</v-layout>
</v-form>
<!-- when comment the above and uncomment the below the error messages disappear -->
<!--<v-form ref="form">-->
<!--<TestStatusSelect-->
<!--ref="testDataSelect"-->
<!--v-model="testData.testStatus"-->
<!--#change="onFormChange($event)"/>-->
<!--</v-form>-->
</template>
The jest-test
import VueTestUtils, {createLocalVue, mount} from "#vue/test-utils";
import Vuex from 'vuex';
import Vuetify from 'vuetify';
import TestForm from "#/components/example/TestForm";
import TestModelData from "#/api/model/example/TestModelData";
VueTestUtils.config.provide['$options'] = {};
const localVue = createLocalVue();
localVue.use(Vuex);
localVue.use(Vuetify);
const TEST_MODEL_DATA = TestModelData.fromJSON({
"id": 1,
"testdata": {
"id": 1,
"name": "Foo",
"testStatus": 0,
}
});
describe('TestForm Tests', () => {
test('TestForm select testStatus', () => {
const setTestData = jest.fn();
const getters = {
"current": jest.fn().mockImplementation(() => {
return TEST_MODEL_DATA;
}),
"hasUnsavedChanges": jest.fn().mockReturnValue(false),
};
const store = new Vuex.Store({
modules: {
testModelData: {
namespaced: true,
getters: getters,
actions: {setTestData}
}
}
});
const wrapper = mount(TestForm, {
store, localVue, propsData: {
testModelData: TEST_MODEL_DATA
}
});
const first = wrapper.findAll('.v-list__tile--link').at(1);
first.trigger('click');
expect(setTestData).toHaveBeenCalled();
});
});
The component TestStatusSelect
<script>
import VSelect from "vuetify/es5/components/VSelect";
import TestStatus from "#/api/model/example/TestStatus";
export default {
components: {
VSelect
},
props: ["value", "disabled"],
data() {
return {
testStatuses: TestStatus.ALL,
testStatus: this.value ? this.value : TestStatus.FIRST
};
},
watch: {
value(val) {
if (this.testStatus.id !== val.id) {
console.log('VALUE');
this.testStatus = val;
}
},
testStatus(val, oldVal) {
if (val.id !== oldVal.id) {
this.$emit("input", val);
this.$emit("change", val);
}
}
}
};
</script>
<template>
<v-select
ref="testStatusSelect"
:disabled="disabled"
label="Result"
:items="testStatuses"
item-text="name"
item-value="id"
v-model="testStatus"
return-object>
</v-select>
</template>
The class TestModelData
import TestData from "#/api/model/example/TestData";
class TestModelData {
constructor() {
this.id = null;
this.testData = null;
}
fromJSON(json) {
this.id = json.id;
this.testData = TestData.fromJSON(json.testData);
}
toJSON() {
const o = {
id: this.id,
};
if (this.testData) {
a.testData = this.testData.toJSON();
}
return o;
}
static fromJSON(json) {
if (!json) {
return null;
} else {
const a = new TestModelData();
a.fromJSON(json);
return a;
}
}
}
export default TestModelData;
The class TestData
import TestStatus from "#/api/model/example/TestStatus";
class TestData {
constructor() {
this.id = null;
this.name = null;
this.testStatus = TestStatus.FIRST;
}
fromJSON(json) {
this.id = json.id;
this.name = json.name;
this.testStatus = json.testStatus !== null ? TestStatus.fromJSON(json.testStatus) : null;
}
toJSON() {
const o = {
id: this.id,
};
o.name = this.name;
o.testStatus = this.testStatus ? this.testStatus.toJSON() : null;
return o;
}
static fromJSON(json) {
if (!json) {
return null;
} else {
const a = new TestData();
a.fromJSON(json);
return a;
}
}
}
export default TestData;
The class TestStatus
import PropTypes from "prop-types";
import Definition from "../Definition";
class TestStatus extends Definition {
constructor(id, name) {
super();
this.id = id;
this.name = name;
}
static FIRST = new TestStatus(0, "first");
static SECOND = new TestStatus(1, "second");
static ALL = [
TestStatus.FIRST,
TestStatus.SECOND
];
toJSON() {
return this.id;
}
static fromJSON(json) {
if (json === TestStatus.FIRST.id) {
return TestStatus.FIRST;
}
else if (json === TestStatus.SECOND.id) {
return TestStatus.SECOND;
}
console.error("TestStatus unknown", json);
throw new Error(`TestStatus ${json} unknown`, json);
}
}
TestStatus.prototype.PROPTYPES = {
id: PropTypes.number,
name: PropTypes.string,
};
export default TestStatus;
The console output
console.error node_modules/#vue/test-utils/dist/vue-test-utils.js:15
[vue-test-utils]: an extended child component <VBtn> has been modified to ensure it has the correct instance properties. This means it is not possible to find the component with a component selector. To find the component, you must stub it manually using the stubs mounting option.
console.error node_modules/#vue/test-utils/dist/vue-test-utils.js:15
[vue-test-utils]: an extended child component <VCard> has been modified to ensure it has the correct instance properties. This means it is not possible to find the component with a component selector. To find the component, you must stub it manually using the stubs mounting option.
console.error node_modules/#vue/test-utils/dist/vue-test-utils.js:15
[vue-test-utils]: an extended child component <VCardTitle> has been modified to ensure it has the correct instance properties. This means it is not possible to find the component with a component selector. To find the component, you must stub it manually using the stubs mounting option.
console.error node_modules/#vue/test-utils/dist/vue-test-utils.js:15
[vue-test-utils]: an extended child component <VCardText> has been modified to ensure it has the correct instance properties. This means it is not possible to find the component with a component selector. To find the component, you must stub it manually using the stubs mounting option.
console.warn node_modules/vuetify/es5/util/console.js:32
[Vuetify] Unable to locate target [data-app]
found in
---> <VMenu>
<VSelect>
<TestStatusSelect>
<VForm>
<VCard>
<Anonymous>
<Root>
console.error node_modules/vue/dist/vue.common.js:593
[Vue warn]: $listeners is readonly.
found in
---> <VSelect>
<TestStatusSelect>
<VForm>
<VCard>
<Anonymous>
<Root>
console.log src/components/example/TestForm.vue:800
Changed: TestStatus {
_clazz: [Getter/Setter],
id: [Getter/Setter],
name: [Getter/Setter] }
console.error node_modules/vue/dist/vue.common.js:593
[Vue warn]: $listeners is readonly.
found in
---> <VSelect>
<TestStatusSelect>
<VForm>
<VCard>
<Anonymous>
<Root>
console.error node_modules/vue/dist/vue.common.js:593
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"
found in
---> <VSelect>
<TestStatusSelect>
<VForm>
<VCard>
<Anonymous>
<Root>
console.error node_modules/vue/dist/vue.common.js:593
[Vue warn]: $listeners is readonly.
found in
---> <VSelect>
<TestStatusSelect>
<VForm>
<VCard>
<Anonymous>
<Root>
There are a few solutions / work arounds in this thread.
This is the one that worked for me, I added it at the top of my test body:
document.body.setAttribute('data-app', true)
find the button by id and triggering a click may occur the warning to resolve this issue consider the below code
let element_forgetBtn = wrapper.find("#forgotPasswordBtn");
> let app = document.createElement("div");
> app.setAttribute("data-app", true);
> document.body.append(app);
element_forgetBtn.trigger("click");
complete code is below
let element_forgetBtn = wrapper.find("#forgotPasswordBtn");
let app = document.createElement("div");
app.setAttribute("data-app", true);
document.body.append(app);
element_forgetBtn.trigger("click");

vue mutation push object reference?

addSentence: (state) => {
const obj = state;
// next line is correct;
obj.sentences.push({ ...obj.current });
// change to next line, get error
// obj.sentences.push(obj.current);
obj.current = new Sentence();
},
import Constants from './Constants';
export default class Sentence {
constructor(config) {
this.text = '';
this.fontFamily = 'KaiTi';
this.fontSize = 16;
this.fontStyle = '';
this.appearStyle = {
name: 'type',
speed: 40,
startDelay: 0,
};
this.disappearStyle = {
name: 'backspace',
speed: 80,
startDelay: 0,
smartBackspace: true,
};
}
play(context) {
}
drawText() {
}
}
state.cuurent is an object of type Sentence.
And state.sentences = [Sentence]
This is a mutation handler.
Error:
[vuex] Do not mutate vuex store state outside mutation handlers.

Jest / Enzyme - How to test at different viewports?

I am trying to run a test on a component at a certain viewport width. I am doing the following, but this doesn't seem to change it:
test('Component should do something at a certain viewport width.', () => {
global.innerWidth = 2000;
const component = mount(<SomeComponent />);
...
});
I also found an article that explains how to do it using JSDom, but as Jest now ships with JSDom, I wondered if there was a native solution.
https://www.codementor.io/pkodmad/dom-testing-react-application-jest-k4ll4f8sd
Background Information:
jsdom does not implement window.resizeBy() or window.resizeTo()
jsdom defines the window innerWidth and innerHeight to be 1024 x 768
It is possible to simulate a window resize using jsdom by manually setting window.innerWidth and window.innerHeight and firing the resize event
Here is an example:
comp.js
import * as React from 'react';
export default class Comp extends React.Component {
constructor(...args) {
super(...args);
this.state = { width: 0, height: 0 }
}
updateDimensions = () => {
this.setState({ width: window.innerWidth, height: window.innerHeight });
}
componentDidMount() {
this.updateDimensions();
window.addEventListener("resize", this.updateDimensions);
}
componentWillUnmount() {
window.removeEventListener("resize", this.updateDimensions);
}
render() {
return <div>{this.state.width} x {this.state.height}</div>;
}
}
comp.test.js
import * as React from 'react';
import { shallow } from 'enzyme';
import Comp from './comp';
const resizeWindow = (x, y) => {
window.innerWidth = x;
window.innerHeight = y;
window.dispatchEvent(new Event('resize'));
}
describe('Comp', () => {
it('should display the window size', () => {
const component = shallow(<Comp />);
expect(component.html()).toEqual('<div>1024 x 768</div>');
resizeWindow(500, 300);
expect(component.html()).toEqual('<div>500 x 300</div>');
resizeWindow(2880, 1800);
expect(component.html()).toEqual('<div>2880 x 1800</div>');
});
});
Notes:
As of Enzyme v3 shallow calls React lifecycle methods like componentDidMount() so it can be used in place of mount
This answer borrows heavily from the information here, here, here, and #JoeTidee's own answer here.
If you're using TypeScript it will complain that window.innerWidth/innerHeight are readonly.
You can get around this with either redeclaring the property:
Object.defineProperty(window, 'innerWidth', {writable: true, configurable: true, value: 105})
or using the Object.assign method:
window = Object.assign(window, { innerWidth: 105 });
Both not extremely nice solutions, but they work.
Works for me. Code is no longer marked as uncovered.
it('resize event listener changes the state', () => {
const wrapper = shallow(<Component />);
const instance = wrapper.instance();
instance.setState({
mobileMode: true
});
global.innerWidth = 800;
window.dispatchEvent(new Event('resize'));
expect(instance.state.mobileMode).toBeFalsy();
global.innerWidth = 600;
window.dispatchEvent(new Event('resize'));
expect(instance.state.mobileMode).toBeTruthy();
});
Resize listener inside my component
...
resizeListener = () => {
if (window.innerWidth < 768) {
this.setState({
mobileMode: true
});
} else {
this.setState({
mobileMode: false
});
}
};
window.addEventListener('resize', resizeListener);
...

react-stockchart: cannot convert JSX to TSX

I have an example of the react-stockchart chart in JSX:
JSX plunker: http://plnkr.co/edit/gist:b993d5fcc5c09dd66a6e?p=preview
I want to add JSX to an existing TypeScript project, so I changed the file extension from JSX to TSX and did other convertions from this site:
http://slidedeck.io/thewazir/Using-Typescript-with-JSX
But the problem still remains, this code doesn't compile:
CandleStickChartWithBollingerBandOverlay = fitWidth(CandleStickChartWithBollingerBandOverlay);
ReactDOM.render(<CandleStickChartWithBollingerBandOverlay data={data} type="hybrid"/>, document.getElementById("chart"));
fitWidth source: https://github.com/rrag/react-stockcharts/blob/master/src/lib/helper/fitWidth.jsx
If I remove fitWidth it is drawn with incorrect width:
ReactDOM.render(<CandleStickChartWithBollingerBandOverlay data={data} type="hybrid" width={800}/>, document.getElementById("chart"));
I tried this code, it doesn't work (nothing is drawn at all):
var StockChartComponent = fitWidth(CandleStickChartWithBollingerBandOverlay);
ReactDOM.render(<StockChartComponent data={data} type="hybrid"/>, document.getElementById("chart"));
And this doesn't work too:
var StockChartComponent = fitWidth(new CandleStickChartWithBollingerBandOverlay());
ReactDOM.render(<StockChartComponent data={data} type="hybrid"/>, document.getElementById("chart"));
This is the main tsx file:
export function initialize(data, element) {
var StockChartComponent = fitWidth(CandleStickChartWithBollingerBandOverlay);
ReactDOM.render(<StockChartComponent data={data} type="hybrid" height={800} />, element);
}
This is the fixed fitWidth.tsx:
import React = require('react');
import ReactDOM = require('react-dom');
export function fitWidth(WrappedComponent, withRef = true) {
class ResponsiveComponent extends React.Component<any, any> {
static getDisplayName(Series) {
var name = Series.displayName || Series.name || "Series";
return name;
}
static defaultProps = {
displayName: `fitWidth(${ResponsiveComponent.getDisplayName(WrappedComponent)})`
}
constructor(props) {
super(props);
this.handleWindowResize = this.handleWindowResize.bind(this);
this.getWrappedInstance = this.getWrappedInstance.bind(this);
}
componentDidMount() {
window.addEventListener("resize", this.handleWindowResize);
var el = ReactDOM.findDOMNode(this);
var w = (el.parentNode as Element).clientWidth;
/* eslint-disable react/no-did-mount-set-state */
this.setState({
width: w
});
/* eslint-enable react/no-did-mount-set-state */
}
componentWillUnmount() {
window.removeEventListener("resize", this.handleWindowResize);
}
handleWindowResize() {
var el = ReactDOM.findDOMNode(this);
var w = (el.parentNode as Element).clientWidth;
this.setState({
width: w
});
}
getWrappedInstance() {
return (this.refs as any).component;
}
render() {
var ref = withRef ? { ref: "component" } : {};
if (this.state && this.state.width) {
return <WrappedComponent width={this.state.width} {...this.props} {...ref} />;
} else {
return <div />;
}
}
}
return ResponsiveComponent;
}

Resources