Giter VIP home page Giter VIP logo

flutter_chatview's Introduction

Banner

ChatView

chatview

A Flutter package that allows you to integrate Chat View with highly customization options such as one on one chat, group chat, message reactions, reply messages, link preview and configurations for overall view.

For web demo visit Chat View Example.

Preview

The example app running in iOS

Installing

  1. Add dependency to pubspec.yaml
dependencies:
  chatview: <latest-version>

Get the latest version in the 'Installing' tab on pub.dev

  1. Import the package
import 'package:chatview/chatview.dart';
  1. Adding a chat controller.
final chatController = ChatController(
  initialMessageList: messageList,
  scrollController: ScrollController(),
  chatUsers: [ChatUser(id: '2', name: 'Simform')],
);
  1. Adding a ChatView widget.
ChatView(
  currentUser: ChatUser(id: '1', name: 'Flutter'),
  chatController: chatController,
  onSendTap: onSendTap,
  chatViewState: ChatViewState.hasMessages, // Add this state once data is available.
)
  1. Adding a messageList with Message class.
List<Message> messageList = [
  Message(
    id: '1',
    message: "Hi",
    createdAt: createdAt,
    sendBy: userId,
  ),
  Message(
    id: '2',
    message: "Hello",
    createdAt: createdAt,
    sendBy: userId,
  ),
];
  1. Adding a onSendTap.
void onSendTap(String message, ReplyMessage replyMessage, MessageType messageType){
  final message = Message(
    id: '3',
    message: "How are you",
    createdAt: DateTime.now(),
    sendBy: currentUser.id,
    replyMessage: replyMessage,
    messageType: messageType,
  );
  chatController.addMessage(message);
}

Note: you can evaluate message type from messageType parameter, based on that you can perform operations.

Messages types compability

Message Types Android iOS MacOS Web Linux Windows
Text messages ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Image messages ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Voice messages ✔️ ✔️
Custom messages ✔️ ✔️ ✔️ ✔️ ✔️ ✔️

Platform specific configuration

For image Picker

iOS

  • Add the following keys to your Info.plist file, located in <project root>/ios/Runner/Info.plist:
    <key>NSCameraUsageDescription</key>
    <string>Used to demonstrate image picker plugin</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>Used to capture audio for image picker plugin</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Used to demonstrate image picker plugin</string>

For voice messages

iOS

  • Add this two rows in ios/Runner/Info.plist
    <key>NSMicrophoneUsageDescription</key>
    <string>This app requires Mic permission.</string>
  • This plugin requires ios 10.0 or higher. So add this line in Podfile
    platform :ios, '10.0'

Android

  • Change the minimum Android sdk version to 21 (or higher) in your android/app/build.gradle file.
    minSdkVersion 21
  • Add RECORD_AUDIO permission in AndroidManifest.xml
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>

Some more optional parameters

  1. Enable and disable specific features with FeatureActiveConfig.
ChatView(
  ...
  featureActiveConfig: FeatureActiveConfig(
    enableSwipeToReply: true,
    enableSwipeToSeeTime: false,
  ),
  ...
)
  1. Adding an appbar with ChatViewAppBar.
ChatView(
  ...
  appBar: ChatViewAppBar(
    profilePicture: profileImage,
    chatTitle: "Simform",
    userStatus: "online",
    actions: [
      Icon(Icons.more_vert),
    ],
  ),
  ...
)
  1. Adding a message list configuration with ChatBackgroundConfiguration class.
ChatView(
  ...
  chatBackgroundConfig: ChatBackgroundConfiguration(
    backgroundColor: Colors.white,
    backgroundImage: backgroundImage,
  ),
  ...
)
  1. Adding a send message configuration with SendMessageConfiguration class.
ChatView(
  ...
  sendMessageConfig: SendMessageConfiguration(
    replyMessageColor: Colors.grey,
    replyDialogColor:Colors.blue,
    replyTitleColor: Colors.black,
    closeIconColor: Colors.black,
  ),
  ...
)
  1. Adding a chat bubble configuration with ChatBubbleConfiguration class.
ChatView(
  ...
  chatBubbleConfig: ChatBubbleConfiguration(
    onDoubleTap: (){
       // Your code goes here
    },
    outgoingChatBubbleConfig: ChatBubble(      // Sender's message chat bubble 
      color: Colors.blue,
      borderRadius: const BorderRadius.only(  
        topRight: Radius.circular(12),
        topLeft: Radius.circular(12),
        bottomLeft: Radius.circular(12),
      ),
    ),
    inComingChatBubbleConfig: ChatBubble(      // Receiver's message chat bubble
      color: Colors.grey.shade200,
      borderRadius: const BorderRadius.only(
        topLeft: Radius.circular(12),
        topRight: Radius.circular(12),
        bottomRight: Radius.circular(12),
      ),
    ),
  )
  ...
)
  1. Adding swipe to reply configuration with SwipeToReplyConfiguration class.
ChatView(
  ...
  swipeToReplyConfig: SwipeToReplyConfiguration(
    onLeftSwipe: (message, sendBy){
        // Your code goes here
    },
    onRightSwipe: (message, sendBy){
        // Your code goes here
    },              
  ),
  ...
)
  1. Adding messages configuration with MessageConfiguration class.
ChatView(
  ...
  messageConfig: MessageConfiguration(
    messageReactionConfig: MessageReactionConfiguration(),      // Emoji reaction configuration for single message 
    imageMessageConfig: ImageMessageConfiguration(
      onTap: (){
          // Your code goes here
      },                          
      shareIconConfig: ShareIconConfiguration(
        onPressed: (){
           // Your code goes here
        },
      ),
    ),
  ),
  ...
)
  1. Adding reaction pop-up configuration with ReactionPopupConfiguration class.
ChatView(
  ...
  reactionPopupConfig: ReactionPopupConfiguration(
    backgroundColor: Colors.white,
    userReactionCallback: (message, emoji){
      // Your code goes here
    }
    padding: EdgeInsets.all(12),
    shadow: BoxShadow(
      color: Colors.black54,
      blurRadius: 20,
    ),
  ),
  ...
)
  1. Adding reply pop-up configuration with ReplyPopupConfiguration class.
ChatView(
  ...
  replyPopupConfig: ReplyPopupConfiguration(
    backgroundColor: Colors.white,
    onUnsendTap:(message){                   // message is 'Message' class instance
       // Your code goes here
    },
    onReplyTap:(message){                    // message is 'Message' class instance
       // Your code goes here
    },
    onReportTap:(){
       // Your code goes here
    },
    onMoreTap:(){
       // Your code goes here
    },
  ),
  ...
)
  1. Adding replied message configuration with RepliedMessageConfiguration class.
ChatView(
   ...
   repliedMessageConfig: RepliedMessageConfiguration(
     backgroundColor: Colors.blue,
     verticalBarColor: Colors.black,
     repliedMsgAutoScrollConfig: RepliedMsgAutoScrollConfig(),
   ),
   ...
)
  1. For customizing typing indicators use typeIndicatorConfig with TypeIndicatorConfig.
ChatView(
  ...

  typeIndicatorConfig: TypeIndicatorConfiguration(
    flashingCircleBrightColor: Colors.grey,
    flashingCircleDarkColor: Colors.black,
  ),
  ...
)
  1. For showing hiding typeIndicatorwidget use ChatController.setTypingIndicaor, for more info see ChatController.
/// use it with your [ChatController] instance.
_chatContoller.setTypingIndicator = true; // for showing indicator
_chatContoller.setTypingIndicator = false; // for hiding indicator
  1. Adding linkpreview configuration with LinkPreviewConfiguration class.
ChatView(
  ...
  chatBubbleConfig: ChatBubbleConfiguration(
    linkPreviewConfig: LinkPreviewConfiguration(
      linkStyle: const TextStyle(
        color: Colors.white,
        decoration: TextDecoration.underline,
      ),
      backgroundColor: Colors.grey,
      bodyStyle: const TextStyle(
        color: Colors.grey.shade200,
        fontSize:16,
      ),
      titleStyle: const TextStyle(
        color: Colors.black,
        fontSize:20,
      ),
    ),
  )
  ...
)
  1. Adding pagination.
ChatView(
  ...
  isLastPage: false,
  featureActiveConfig: FeatureActiveConfig(
    enablePagination: true,
  ),
  loadMoreData: chatController.loadMoreData,
  ...
)
  1. Add image picker configuration.
ChatView(
  ...
  sendMessageConfig: SendMessageConfiguration(
    enableCameraImagePicker: false,
    enableGalleryImagePicker: true,
    imagePickerIconsConfig: ImagePickerIconsConfiguration(
      cameraIconColor: Colors.black,
      galleryIconColor: Colors.black,
    )
  )
  ...
)
  1. Add ChatViewState customisations.
ChatView(
  ...
  chatViewStateConfig: ChatViewStateConfiguration(
    loadingWidgetConfig: ChatViewStateWidgetConfiguration(
      loadingIndicatorColor: Colors.pink,
    ),
    onReloadButtonTap: () {},
  ),
  ...
)
  1. Setting auto scroll and highlight config with RepliedMsgAutoScrollConfig class.
ChatView(
    ...
    repliedMsgAutoScrollConfig: RepliedMsgAutoScrollConfig(
      enableHighlightRepliedMsg: true,
      highlightColor: Colors.grey,
      highlightScale: 1.1,
    )
    ...
)
  1. Callback when a user starts/stops typing in TextFieldConfiguration
ChatView(
    ...
      sendMessageConfig: SendMessageConfiguration(
       
          textFieldConfig: TextFieldConfiguration(
            onMessageTyping: (status) {
                // send composing/composed status to other client
                // your code goes here
            },   

            
        /// After typing stopped, the threshold time after which the composing
        /// status to be changed to [TypeWriterStatus.typed].
        /// Default is 1 second.
            compositionThresholdTime: const Duration(seconds: 1),

        ),
    ...
  )
)
  1. Passing customReceipts builder or handling stuffs related receipts see ReceiptsWidgetConfig in outgoingChatBubbleConfig.
ChatView(
   ...
      featureActiveConfig: const FeatureActiveConfig(
            /// Controls the visibility of message seen ago receipts default is true
            lastSeenAgoBuilderVisibility: false,
            /// Controls the visibility of the message [receiptsBuilder]
            receiptsBuilderVisibility: false),            
       ChatBubbleConfiguration(
          inComingChatBubbleConfig: ChatBubble(
            onMessageRead: (message) {
              /// send your message reciepts to the other client
              debugPrint('Message Read');
            },

          ),
          outgoingChatBubbleConfig: ChatBubble(
              receiptsWidgetConfig: ReceiptsWidgetConfig(
                      /// custom receipts builder 
                      receiptsBuilder: _customReceiptsBuilder,
                      /// whether to display receipts in all 
                      /// message or just at the last one just like instagram
                      showReceiptsIn: ShowReceiptsIn.lastMessage
              ),
            ), 
        ), 
        
  ...
 
)

How to use

Check out blog for better understanding and basic implementation.

Also, for whole example, check out the example app in the example directory or the 'Example' tab on pub.dartlang.org for a more complete example.

Main Contributors


Vatsal Tanna

Dhvanit Vaghani

Ujas Majithiya

License

MIT License
Copyright (c) 2022 Simform Solutions
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

flutter_chatview's People

Contributors

dhavalrkansara avatar dhvanit-v-simformsolutions avatar dhvanitvaghani avatar jaiminrana avatar jsmistry2000 avatar mobile-simformsolutions avatar rohitsangwan01 avatar s4nk37 avatar ujas-m-simformsolutions avatar uzzero avatar vatsaltanna avatar vatsaltanna-simformsolutions avatar yogesh-dubey-ayesavi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

flutter_chatview's Issues

How do I add time to a date?

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

input event

Please add a listener event to the message input to get the current content being typed, thanks!

Support For CupertinoApp

When embedding it in CupertinoApp throws the error ScaffoldMessenger not found, Is there any way to add it in CupertionApp.

Message Seen

I think we should work on message-seen functionality, just like Instagram whether the message is seen or not will be visible in the last message only.

Add image picker

Is your feature request related to a problem? Please describe.
No

Describe the solution you'd like
Add a button to pick image and in return it gives image data in call back.

reply message

Hello, is it possible to add click on the message and scroll to the replayed message?

Callback on reaction.

I went through the documentation i didn't found any callback when a message is reacted? How to notify other users regarding reactions.

Add Giphy Support

Any smart person
Please can you assist with adding Giphy Support on the plugin :)

"extra" field for Message class

Is your feature request related to a problem? Please describe.
Thanks for your amazing job, it's really helpful to add chat with this package, I think for more convenience you'd better to add a field for custom use like "extra" or "additionalData" etc.

Load more data is not working properly

The features are really cool, thank you for creating them!

Describe the bug
Unfortunately, loadMoreData callback is being called when I reach the bottom of the chat.

Keyboard glicth

I'm having trouble opening the keyboard when the message content is too much. I couldn't understand what the problem was and tried many solutions but none of them solved this problem.
(A chat stream of about 200 lines)

android and ios

Can't remove the reaction

We can't remove the reaction it we accidentally give reaction then there is no option to remove the reaction

Discussions

Can you please open discussions panel in order to discuss some upcoming blazing features and current updates?

markdown support

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

emoji and text

iPhone 7 Plus
Flutter 3.0.1
chat_view 0.0.1

When text and emoji are used together, the background and text style aren't look right.

0_FA2C48F3-1F9B-404D-B742-AC6AAF08DC35-85663

MessageType.video support or better MessageType.custom

Video support
Similar to MessageType.image, MessageType.video is an essential part of any chat app. It is a must-have.

Also any way of having custom types? A sizedbox is provided to the dev.
Dev can add custom types to enum, Dev can develop his own Widget inside that view for this new type.

loadMoreData error

When the loadMoreData callback is called, I get to the bottom of the chat instead of the top of the chat.

Group chat

Any future plans, to enable group chat?
At the moment only 2 people can be involved in a chat.

This will help in situations like a comment section of an App

Unnecessary Rebuilds

I just added to debugPrint('${widget.message.id} rebuilt'); to MessageView build method .

The logs i obtained then.

a0e30af0-daa0-46fa-a1f8-54af63a743ac.mp4

Each message even which are outside the viewPort are getting rebuilt, that causes huge memory consumption.

Ability to switch off "bells and whistles"

I would use the chatview for a Duolingo like of conversation display, that I would play out a conversation as if it were in a chat window.

For this, I would need:

  • both particpants avatar to be shown, not just the other side who is not the current user
  • switch the display of the send bar on the bottom OFF
  • remove the possiblity to reply on the message bubble
  • remove reactions on the message bubble
  • remove the swipe option

I could also fork this repo and do these, but I was wondering if this maybe a generic enough request so that I would be useful for others too. :)

Thanks a lot in advance!

Audiowaveform crashes the app if the audio file does not exist

Describe the bug
Audiowaveform crashes the app if the audio file does not exist

To Reproduce
Steps to reproduce the behavior:

  1. Create a chat with audio message and store the message history somewhere locally (Hive)
  2. Clear the cache on simulator (tmp directory)
  3. Open the chat again
  4. See error

Expected behavior
The lib should check if the file exists, if not, it should throw a better error message, cause right now it only says "Platform codec failed" which is vague.
It would be nice to have an ability to set the directory where the audio files will be saved, so that we can select a permanent location instead of some temp folder

Idempotense to add message

First off - I really enjoy your package 👍

Is your feature request related to a problem? Please describe.
add message needs to be idempotent in order to handle duplicate messages from Firebase or a REST API

Describe the solution you'd like

Here is some code I added that can do it

  void addMessage(Message message) {
    // Add or update?

    bool found = false;

    for (int i = 0; i < initialMessageList.length; i++) {
      if (initialMessageList[i].id == message.id) {
        initialMessageList[i] = message; // Update the item if id is found
        found = true;
        // print("Update with id " + message.id);
        break;
      }
    }

    if (!found) {
      // print("Add with id " + message.id);
      initialMessageList.add(message); // Add the item if id is not found
    }
    // initialMessageList.add(message);
    messageStreamController.sink.add(initialMessageList);
  }

Question ⁉️ Is this repo still maintained

This is a very good plugin, I see alot of effort has been put into building this.

This plugin depends on quite a few packages, which will in return cause version conflicts if package is not frequently updated.

My questions are
Is this package abandoned?

I haven't seen any action in 2 months now.
Can we atlest update dependancies.

I was gonna open a pull request, but then I see all PR are not getting merged.

I understand you guys are busy with actual office work projects and may not have the time for this anymore

TextField controler

Please add a function to be able to write to the message TextField and get and control the focus state. Thank you!

Remote audio not working

Don't have anything about the audio in exemples and docs.
I has tried play that via network from my servers, like I do photos, but the audio function not working.

Its sound like if the package is trying play from local folder.

I have to download the files before play the audio?

Can someone clarify it, please?

Who is typing

Is your feature request related to a problem? Please describe.
It would be be better to also show "who is typing" in the typing widget - at least users profile photo

Describe the solution you'd like
Currently, in a group chat, it's just showing a placeholder profile photo about who is typing, but it will be better also setting the users ID about who is typing...

Describe alternatives you've considered
maybe we can set as

 chatViewController.setTypingIndicator = true;
chatViewController.setTypingUserID = "something"

and so typing indicator can show who is typing.

Additional context
Add any other context or screenshots about the feature request here.

Text markdown support

hi, can text support markdown on text messages? I want use it build chatbot and should need parse markdown response from ChatGPT

Image not able to load from memory

Describe the bug
An error of The following ArgumentError was thrown resolving an image codec: Invalid argument(s): No host specified in URI file:///private/var/mobile/Containers/Data/Application/663B9B55-3FC3-4D72-B21D-CC14A69EED28/tmp/image_picker_E4842E9F-CA6B-48FA-A4E3-ED138AD1D794-8270-000005E06656CA94.jpg is thrown whenever I try to send an image from my device.

Expected behavior
I expected an image to be sent from the device as a message but it throws an error.

Screenshots
This is how it is appearing
IMG_0348

Screenshot 2023-02-26 at 5 56 17 PM

From the above image, I think its trying to use NetworkImage to load the image, meanwhile I picked the image from memory. I think the problem is coming from the extension you're using to detect whethe its a network image or not(```.fromMemory```)

Desktop (please complete the following information):

  • OS: macOS

Smartphone (please complete the following information):

  • Device: Iphone 11
  • OS: iOS 16.2

Can you please introduce voice message also then it will be more better and perfect I think this feature will come soon

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Improper Configurations

Well talking about the UI, it's a good package but when considering performance it isn't. Well, I found some issues I would like to address it.

Types
Types are not well defined, for instance talking about Message class

Message class should be an interface or abstract class where as TextMessage, ImageMessage, VoiceMessage should be child classes of parent message class that will allow having more functionalities related to particular messages. For example considering an ImageMessage if a user has to send an image message as of now he has to load it somewhere get url then send image url as messageType image, what if he wants to send the image message from memory or uint8list there are a lot of functionalities and attributes are which are instance or message specific i think we should them because everything cannot be simply converted into Text.

In sentTo and sentBy instead of String data type it should be ChatUser directly i think that will be more feasible

I'am not getting why is replyMessage a separate class it should be a type of message only , why does every message contains a default replyMessage it should be nullable

MessageState

What about MessageStates whether the message is delivered undelivered pending states there should be some options for them too,

UI Rerenders
While testing i found unnecessary ui rerenders i think RepaintBoundary widgets must be wrapped around animating widgets also i found setState method is widely used inside the library which should be replaced with ValueNotifiers and ValueListenableBuilders.

Unsend & Read receipt status

Is your feature request related to a problem? Please describe.
I'm playing around try to add chat to our app. But I haven't found a way to unsend the message and add Read Receipt status for each/ group of messages.

Unsend a message.
I want to be able to unsend a specific message, and replace with another UI like Facebook.
Currently the controller doesn't have unsend/delete function and the Message don't have any property to indicate which message was deleted/ unsent.

This is the UI that I want to archive.
image

Read Receipt status
On the folder preview -> reciepts_test.gif I saw that you guys have that feature. But when I try the example with latest version. I don't have option/ configuration to enable that. So how can I archive this ?

Thanks.

Audio message not working

Describe the bug
I am trying to record an audio message but it never works on my device

It gives me an error of [VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(AudioWaveforms, Failed to prepare player, null, null)

[✓] Flutter (Channel stable, 3.7.1, on macOS 13.0.1 22A400 darwin-x64, locale en-GH)
Checking Android licenses is taking an unexpectedly long time...[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 14.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.3)
[✓] VS Code (version 1.75.1)
[✓] Connected device (2 available)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.