Giter VIP home page Giter VIP logo

ttkscrollablenotebook's People

Contributors

aussig avatar moosems avatar muhammeteminturgut avatar

Stargazers

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

Watchers

 avatar

ttkscrollablenotebook's Issues

ScrollableNotebook grid implementation

I am new to python and tkinter, I found it useful in my code to change the geometry manager of youre library from pack to grid.
posting it here, maybe it would help someone.

from tkinter import *
from tkinter import ttk


class ScrollableNotebook(ttk.Frame):
    def __init__(self, parent, wheelscroll=True, tabmenu=True, *args, **kwargs):
        super().__init__(master=parent)
        self.grid(row=2, column=1, columnspan=2, sticky="nswe")
        self.grid_rowconfigure(0, weight=1)
        self.configure(style='Custom.TFrame')
        self.xLocation = 0
        self.notebookContent = ttk.Notebook(self)
        self.notebookContent.grid(sticky="nswe")
        self.notebookTab = ttk.Notebook(self)
        self.notebookTab.bind("<<NotebookTabChanged>>", self._tabChanger)
        if wheelscroll:
            self.notebookTab.bind("<MouseWheel>", self._wheelscroll)
        slide_frame = ttk.Frame(self)
        self.menuSpace = 50
        if tabmenu:
            self.menuSpace = 50
            bottom_tab = ttk.Label(slide_frame, text="\u2630")
            bottom_tab.bind("<ButtonPress-1>", self._bottomMenu)

        left_arrow = ttk.Label(slide_frame, text=" \u276E")
        left_arrow.bind("<ButtonPress-1>", self._leftSlideStart)
        left_arrow.bind("<ButtonRelease-1>", self._slideStop)
        right_arrow = ttk.Label(slide_frame, text=" \u276F")
        right_arrow.bind("<ButtonPress-1>", self._rightSlideStart)
        right_arrow.bind("<ButtonRelease-1>", self._slideStop)
        self.notebookContent.bind("<Configure>", self._resetSlide)
        self.contentsManaged = []

        slide_frame.grid(row=0, column=1, sticky="nswe")
        bottom_tab.grid(row=0, column=1)
        left_arrow.grid(row=0, column=0)
        right_arrow.grid(row=0, column=2)

    def _wheelscroll(self, event):
        if event.delta > 0:
            self._leftSlide(event)
        else:
            self._rightSlide(event)

    def _bottomMenu(self, event):
        tab_list_menu = Menu(self, tearoff=0)
        for tab in self.notebookTab.tabs():
            tab_list_menu.add_command(label=self.notebookTab.tab(tab, option="text"),
                                      command=lambda temp=tab: self.select(temp))
        try:
            tab_list_menu.tk_popup(event.x_root, event.y_root)
        finally:
            tab_list_menu.grab_release()

    def _tabChanger(self, event):
        try:
            self.notebookContent.select(self.notebookTab.index("current"))
        except:
            print("problem")

    def _rightSlideStart(self, event=None):
        if self._rightSlide(event):
            self.timer = self.after(100, self._rightSlideStart)

    def _rightSlide(self, event):
        if self.notebookTab.winfo_width() > self.notebookContent.winfo_width() - self.menuSpace:
            if (self.notebookContent.winfo_width() - (
                    self.notebookTab.winfo_width() + self.notebookTab.winfo_x())) <= self.menuSpace + 5:
                self.xLocation -= 20
                self.notebookTab.place(x=self.xLocation, y=0)
                return True
        return False

    def _leftSlideStart(self, event=None):
        if self._leftSlide(event):
            self.timer = self.after(100, self._leftSlideStart)

    def _leftSlide(self, event):
        if not self.notebookTab.winfo_x() == 0:
            self.xLocation += 20
            self.notebookTab.place(x=self.xLocation, y=0)
            return True
        return False

    def _slideStop(self, event):
        if self.timer is not None:
            self.after_cancel(self.timer)
            self.timer = None

    def _resetSlide(self, event=None):
        self.notebookTab.place(x=0, y=0)
        self.xLocation = 0

    def add(self, frame, **kwargs):
        if len(self.notebookTab.winfo_children()) != 0:
            self.notebookContent.add(frame, text="", state="hidden")
        else:
            self.notebookContent.add(frame, text="")
        self.notebookTab.add(ttk.Frame(self.notebookTab), **kwargs)
        self.contentsManaged.append(frame)

    def forget(self, tab_id):
        index = self.notebookTab.index(tab_id)
        self.notebookContent.forget(self.__ContentTabID(tab_id))
        self.notebookTab.forget(tab_id)
        self.contentsManaged[index].destroy()
        self.contentsManaged.pop(index)

    def hide(self, tab_id):
        self.notebookContent.hide(self.__ContentTabID(tab_id))
        self.notebookTab.hide(tab_id)

    def identify(self, x, y):
        return self.notebookTab.identify(x, y)

    def index(self, tab_id):
        return self.notebookTab.index(tab_id)

    def __ContentTabID(self, tab_id):
        return self.notebookContent.tabs()[self.notebookTab.tabs().index(tab_id)]

    def insert(self, pos, frame, **kwargs):
        self.notebookContent.insert(pos, frame, **kwargs)
        self.notebookTab.insert(pos, frame, **kwargs)

    def select(self, tab_id):
        # self.notebookContent.select(self.__ContentTabID(tab_id))
        self.notebookTab.select(tab_id)

    def tab(self, tab_id, option=None, **kwargs):
        kwargs_content = kwargs.copy()
        kwargs_content["text"] = ""  # important
        self.notebookContent.tab(self.__ContentTabID(tab_id), option=None, **kwargs_content)
        return self.notebookTab.tab(tab_id, option=None, **kwargs)

    def tabs(self):
        # return self.notebookContent.tabs()
        return self.notebookTab.tabs()

    def enable_traversal(self):
        self.notebookContent.enable_traversal()
        self.notebookTab.enable_traversal()

passing nothing to .select should return current tab_id but doesn't

Greetings,
I was trying to use ttkScrollableNotebook in my application. I didn't want to keep adjusting the size of the program to accommodate new tabs so I saw the reference to your library on Stack Overflow.
For the most part the use is almost the same as the original. I included your file and changed the name from notebook to scrollablenotebook and it seemed to work.

The issue I am running into is that when you call the select method without a parameter (tab id) it is suppose to return the current tab_id. Since this is a feature that my program uses I was wondering if this is something you planned to look into.
Thanks in advance.
Peter Hedlund.

Error creating tab

When I create a tab it gives the error:

Traceback (most recent call last):
  File "/Users/joshyacktman/Documents/PyApps/Working/JDE/test2.py", line 155, in <module>
    notebook.add(text_piece, text="Untitled")
  File "/Users/joshyacktman/Documents/PyApps/Working/JDE/ttkScrollableNotebook.py", line 67, in add
    if len(self.notebookTab.winfo_children())!=0:
AttributeError: 'CustomNotebook' object has no attribute 'notebookTab'

What should I do?

.select(tab_id) throws exception

I am using a custom class which inherits from your package
image

line 307 throws:
_tkinter.TclError: .!plotsnotebook.!frame12 is not managed by .!plotsnotebook.!notebook2
image

after looking in the sources,
I've managed to overpass this problem with the commented line 308 as in the photo above

picture of stack:
image

Buttons don't cover the whole tab area

If you use the clam theme on Macosx and create a few tabs the buttons will not cover the entire tab and it looks kind of janky.

Code:

from tkinter import Tk, Text
from tkinter import ttk
from ScrollableNotebook import ScrollableNotebook
root = Tk()
root.title("Scrollable Notebook")
root.geometry("500x500")
s = ttk.Style()
s.theme_use("clam")
counter = 0
notebook = ScrollableNotebook(root, tabmenu=True, wheelscroll=True)
notebook.pack(fill="both", expand=True)
frames = []
def remove_tab():
    current_index = notebook.index("current")
    notebook.forget(notebook.tabs()[current_index])
    try:
        frames[current_index-1].focus_set()
    except:
        pass
def add_tab():
    global counter
    frame = Text(notebook)
    frame.pack(fill="both", expand=True)
    frames.append(frame)
    notebook.add(frame, text="Tab {}".format(counter))
    tabid = notebook.tabs()[-1]
    notebook.select(tabid)
    frames[-1].focus_set()
    counter += 1
ttk.Button(root, text="Remove", command=remove_tab).pack()
ttk.Button(root, text="Add", command=add_tab).pack()
add_tab()
frames[0].focus_set()
def focus_current(event):
    current_focus = notebook.index("current")
    frames[current_focus].focus_set()
root.bind("<Button-1>", focus_current)
root.mainloop()

Image:

Screen Shot 2022-06-09 at 4 48 00 PM

.tab doesn't work

Gives error:

Traceback (most recent call last):
  File "/Users/Moosems/Desktop/JDE/JDE.py", line 72, in <module>
    main_notebook.tab(text_boxes[current_focus], text="Untitled.py")
  File "/Users/Moosems/Desktop/JDE/ttkScrollableNotebook.py", line 202, in tab
    self.notebookContent.tab(self.__ContentTabID(tab_id), option=None, **kwargs_Content)
  File "/Users/Moosems/Desktop/JDE/ttkScrollableNotebook.py", line 189, in __ContentTabID
    return self.notebookContent.tabs()[self.notebookTab.tabs().index(tab_id)]
ValueError: tuple.index(x): x not in tuple

tab_id is not the same for notebookContent and notebookTab @ Python 2

Hi,

Congratulations for the version of ttk.Notebook, you save my life ;)

While replace my old code with ScrollableNotebook, I notice some issues.

The first is because tkinter does not give the same tab_id for notebookContent and notebookTab
Also _tabChanger crash after hiding all my tabs (I'm reusing tabs)
I also find very useful to bind mouse scroll to move the tabs
self.notebookTab.bind("", self._wheelscroll)

To overcome issues I manage to create a function that gives the correct tab_id.
Please review my changes in the code and let me know if they are useful to you

# -*- coding: utf-8 -*-

# Copyright (c) Muhammet Emin TURGUT 2020
# For license see LICENSE
from tkinter import *
from tkinter import ttk

class ScrollableNotebook(ttk.Frame):
    def __init__(self,parent,*args,**kwargs):
        ttk.Frame.__init__(self, parent, *args)
        self.xLocation = 0
        self.notebookContent = ttk.Notebook(self,**kwargs)
        self.notebookContent.pack(fill="both", expand=True)

        self.notebookTab = ttk.Notebook(self,**kwargs)
        self.notebookTab.bind("<<NotebookTabChanged>>",self._tabChanger)
        self.notebookTab.bind("<MouseWheel>", self._wheelscroll)

        slideFrame = ttk.Frame(self)
        slideFrame.place(relx=1.0, x=0, y=1, anchor=NE)
        leftArrow = ttk.Label(slideFrame, text=" ❮")
        leftArrow.bind("<1>",self._leftSlide)
        leftArrow.pack(side=LEFT)
        rightArrow = ttk.Label(slideFrame, text=" ❯ ")
        rightArrow.bind("<1>",self._rightSlide)
        rightArrow.pack(side=RIGHT)
        self.notebookContent.bind("<Configure>", self._resetSlide)

    def _wheelscroll(self, event):
        if event.delta > 0:
            self._leftSlide(event)
        else:
            self._rightSlide(event)

    def _tabChanger(self,event):
        try: self.notebookContent.select(self.notebookTab.index("current"))
        except: pass

    def _rightSlide(self,event):
        if self.notebookTab.winfo_width()>self.notebookContent.winfo_width()-30:
            if (self.notebookContent.winfo_width()-(self.notebookTab.winfo_width()+self.notebookTab.winfo_x()))<=35:
                self.xLocation-=20
                self.notebookTab.place(x=self.xLocation,y=0)
    def _leftSlide(self,event):
        if not self.notebookTab.winfo_x()== 0:
            self.xLocation+=20
            self.notebookTab.place(x=self.xLocation,y=0)

    def _resetSlide(self,event=None):
        self.notebookTab.place(x=0,y=0)
        self.xLocation = 0

    def add(self,frame,**kwargs):
        if len(self.notebookTab.winfo_children())!=0:
            self.notebookContent.add(frame, text="",state="hidden")
        else:
            self.notebookContent.add(frame, text="")
        self.notebookTab.add(ttk.Frame(self.notebookTab),**kwargs)

    def forget(self,tab_id):
        self.notebookContent.forget(self.__ContentTabID(tab_id))
        self.notebookTab.forget(tab_id)

    def hide(self,tab_id):
        self.notebookContent.hide(self.__ContentTabID(tab_id))
        self.notebookTab.hide(tab_id)

    def identify(self,x, y):
        return self.notebookTab.identify(x,y)

    def index(self,tab_id):
        return self.notebookTab.index(tab_id)

    def __ContentTabID(self,tab_id):
        return self.notebookContent.tabs()[self.notebookTab.tabs().index(tab_id)]

    def insert(self,pos,frame, **kwargs):
        self.notebookContent.insert(pos,frame, **kwargs)
        self.notebookTab.insert(pos,frame,**kwargs)

    def select(self,tab_id):
##        self.notebookContent.select(self.__ContentTabID(tab_id))
        self.notebookTab.select(tab_id)

    def tab(self,tab_id, option=None, **kwargs):
        kwargs_Content = kwargs.copy()
        kwargs_Content["text"] = "" # important
        self.notebookContent.tab(self.__ContentTabID(tab_id), option=None, **kwargs_Content)
        return self.notebookTab.tab(tab_id, option=None, **kwargs)

    def tabs(self):
##        return self.notebookContent.tabs()
        return self.notebookTab.tabs()

    def enable_traversal(self):
        self.notebookContent.enable_traversal()
        self.notebookTab.enable_traversal()

Problem closing tab:

Hi I have been able to, implement your code to mine, and in addition add it, the buttons to close tab, that we have answer in a photo.

3

And I have a problem closing, the pestles, when I change the name of the tab, I see that they are created, some nameless windows, nothing like it comes out in the image

1
2

when in the pricipal window of workspapce, open DEVIATIONS, with this code:

def open issuesDeviation (self): global deviation deviation = Deviation (self.notebook) self.cuaderno.add (deviation, text= 'Issues DEVIATIONS') deviting.clean_Widgets ()

self.notebook, call your code:

self.notebook = ScrollableNotebook( self.root, tabmenu = True) self.containedor= ttk.Frame (self.notebook) self.containedor.columnconfigure (1, weight= 1) self.containedor.rowconfigure (1, weight= 1) self.logbook .add(self.container, text='WorkSpace ', underline= 0) self.pack .pack (fill="both ", expand=True)

when I open, the option menu, and I choose an option I change, the name of the tab, the function to the call is:

def change_NamePestana (self, customer): app.cuaderno.tab( idOpenTab, option = None, text = 'DEVIATIONS: {}' .format (customer))
then, when I close the tabs, with the X button on the tab, I close it but, as you see these tabs are created without names and it is annoying, some suggestion, you have passed the code, yours and the one to close the tabs, with stylo and that as I have ..

`

> # -*- coding: utf-8 -*-
> 
> # Copyright (c) Muhammet Emin TURGUT 2020
> # For license see LICENSE
> from os import sendfile
> from tkinter import *
> from tkinter import ttk
> import tkinter as tk
> import tkinter.font as tkFont
> id_tab = 0
> class ScrollableNotebook(ttk.Frame):
>     _initialized = False
>     def __init__(self,parent,wheelscroll=False,tabmenu=False,*args,**kwargs):
>         ttk.Frame.__init__(self, parent, *args)
>         if not self._initialized:
>             self._initialize()
>             self._inititialized = True
>         kwargs["style"] = "ScrollableNotebook"
>         self._active = None
>         self.xLocation = 0
>         self.notebookContent = ttk.Notebook(self,**kwargs)
>         self.notebookContent.pack(fill="both", expand=True)
>         self.notebookTab = ttk.Notebook(self,**kwargs)
>         self.notebookTab.bind("<<NotebookTabChanged>>",self._tabChanger)
>         if wheelscroll==True: self.notebookTab.bind("<MouseWheel>", self._wheelscroll)
>         slideFrame = ttk.Frame(self)
>         slideFrame.place(relx=1.0, x=0, y=1, anchor=NE)
>         self.menuSpace=30
>         if tabmenu==True:
>             self.menuSpace=50
>             bottomTab = ttk.Label(slideFrame, 
>                                 text=" \u2630 ", 
>                                 background='red',
>                                 width=4,
>                                 anchor='center'
>                                 )
>             bottomTab.bind("<1>",self._bottomMenu)
>             bottomTab.pack(side=RIGHT, ipady=10)
>         leftArrow = ttk.Label(slideFrame, text=" \u276E")
>         leftArrow.bind("<1>",self._leftSlide)
>         leftArrow.pack(side=LEFT)
>         rightArrow = ttk.Label(slideFrame, text=" \u276F")
>         rightArrow.bind("<1>",self._rightSlide)
>         rightArrow.pack(side=LEFT)
>         self.notebookContent.bind("<Configure>", self._resetSlide)
>         self.notebookTab.bind("<ButtonPress-1>", self.on_tab_close_press, True)
>         self.notebookTab.bind("<ButtonRelease-1>", self.on_tab_close_release)
>         
>     def on_tab_close_press(self, event):
>         name = self.identify(event.x, event.y)
>         if name == "tab_btn_close":
>             index = self.index("@%d,%d" % (event.x, event.y))
>             self.state(['pressed'])
>             self._active = index
>     
>     def on_tab_close_release(self, event):
>         if not self.instate(['pressed']):
>             return None
>         name =  self.identify(event.x, event.y)
>         print(name)
>         if name == "tab_btn_close":
>             index = self.index("@%d,%d" % (event.x, event.y))
>             if index != 0:
>                 if self._active == index:
>                     print('id al cerrar : <<{}>>'.format(index))
>                     self.forget(index)
>                     self.event_generate("<<NotebookTabClosed>>")
>         self.state(["!pressed"])
>         self._active = None
>     
>     def _initialize(self):
>         self.style = ttk.Style()
>         self.images = (
>             tk.PhotoImage("im1", data='''
>                           R0lGODlhCAAIAMIEAAAAAP/SAP/bNNnZ2f///////////////yH5
>                           BAEKAAIALAAAAAAIAAgAAAMUCCAsCmO5OBVl8OKhoV3e9jQOkAAAOw==
>                            '''),
>             tk.PhotoImage("im2", data='''
>                           R0lGODlhCAAIAMIEAAAAAP/SAP/bNNnZ2f///////////////yH5
>                           BAEKAAMALAAAAAAIAAgAAAMPCDA8+gw+GGlVbWKqmwMJADs=
>                           ''' ),
>             tk.PhotoImage("im3", data='''
>                           R0lGODlhCAAIAMIEAAAAAP/SAP/bNNnZ2f///////////////yH5B
>                           AEKAAMALAAAAAAIAAgAAAMPGDE8+gw+GGlVbWKqmwsJADs=
>                           ''')
>         )
>         self.style.element_create("tab_btn_close", "image", "im1",
>                             ("active", "pressed", "!disabled", "im2"),
>                             ("active", "!disabled", "im3"), border=8, sticky='')
>         self.style.layout("ScrollableNotebook", [("ScrollableNotebook.client", {"sticky": "nswe"})])
>         self.style.layout("ScrollableNotebook.Tab", [
>             ("ScrollableNotebook.tab", {
>                 "sticky": "nswe", 
>                 "children": [
>                     ("ScrollableNotebook.padding", {
>                         "side": "top", 
>                         "sticky": "nswe",
>                         "children": [
>                             ("ScrollableNotebook.focus", {
>                                 "side": "top", 
>                                 "sticky": "nswe",
>                                 "children": [
>                                     ("ScrollableNotebook.label", {"side": "left", "sticky": ''}),
>                                     ("ScrollableNotebook.tab_btn_close", {"side": "left", "sticky": ''}),
>                                 ]
>                             })
>                         ]
>                     })
>                 ]
>             })
>         ])
>         self.style.configure('ScrollableNotebook',
>                             background='#082032'
>         )
>         self.style.configure("ScrollableNotebook.Tab",
>             background='#FDD2BF',
>             foreground='#012443',
>             padding=[20, 10],
>         )         
>         self.style.map('ScrollableNotebook.Tab', background = [("selected", "#B61919"),
>                                                       ("active", "#FF6B6B")],
>                                         foreground = [("selected", "#ffffff"),
>                                                       ("active", "#012443")]
>                  )
> 
>     def _wheelscroll(self, event):
>         if event.delta > 0:
>             self._leftSlide(event)
>         else:
>             self._rightSlide(event)
> 
>     def _bottomMenu(self,event):
>         self.text_font = tkFont.Font(family='Consolas', size=13)
>         tabListMenu = Menu(self, tearoff = 0)
>         for tab in self.notebookTab.tabs():
>             tabListMenu.add_command(label=self.notebookTab.tab(tab, option="text"),
>                                     command= lambda temp=tab: self.select(temp),
>                                     background='#ccffff', 
>                                     foreground='black',
>                                     font=self.text_font,
>                                     activebackground='#004c99',
>                                     activeforeground='white')
>         try: 
>             tabListMenu.tk_popup(event.x_root, event.y_root) 
>         finally: 
>             tabListMenu.grab_release()
> 
>     def _tabChanger(self,event):
>         try:
>             self.notebookContent.select(self.notebookTab.index("current"))
>             # tab_id = self.notebookTab.index("current")
>             # print('id al cambiar : --> ',self.notebookTab.index(self.notebookTab.select()))
>             # global id_tab
>             # id_tab = self.notebookTab.index(self.notebookTab.select())
>             # return tab_id
>         except: pass
> 
>     def _rightSlide(self,event):
>         if self.notebookTab.winfo_width()>self.notebookContent.winfo_width()-self.menuSpace:
>             if (self.notebookContent.winfo_width()-(self.notebookTab.winfo_width()+self.notebookTab.winfo_x()))<=self.menuSpace+5:
>                 self.xLocation-=20
>                 self.notebookTab.place(x=self.xLocation,y=0)
>     
>     def _leftSlide(self,event):
>         if not self.notebookTab.winfo_x()== 0:
>             self.xLocation+=20
>             self.notebookTab.place(x=self.xLocation,y=0)
> 
>     def _resetSlide(self,event):
>         self.notebookTab.place(x=0,y=0)
>         self.xLocation = 0
> 
>     def add(self,frame,**kwargs):
>         if len(self.notebookTab.winfo_children())!=0:
>             self.notebookContent.add(frame, text="",state="hidden")
>         else:
>             self.notebookContent.add(frame, text="")
>         self.notebookTab.add(ttk.Frame(self.notebookTab),**kwargs)
> 
>     def forget(self,tab_id):
>         #self.notebookContent.forget(self.__ContentTabID(tab_id))
>         self.notebookTab.forget(tab_id)
> 
>     def hide(self,tab_id):
>         #self.notebookContent.hide(self.__ContentTabID(tab_id))
>         self.notebookTab.hide(tab_id)
> 
>     def identify(self,x, y):
>         return self.notebookTab.identify(x,y)
> 
>     def index(self,tab_id):
>         return self.notebookTab.index(tab_id)
> 
>     def __ContentTabID(self,tab_id):
>         return self.notebookContent.tabs()[self.notebookTab.tabs().index(tab_id)]
> 
>     def insert(self,pos,frame, **kwargs):
>         self.notebookContent.insert(pos,frame, **kwargs)
>         self.notebookTab.insert(pos,frame,**kwargs)
> 
>     def select(self,tab_id):
>         ##        self.notebookContent.select(self.__ContentTabID(tab_id))
>         self.notebookTab.select(tab_id)
> 
>     def tab(self,tab_id, option=None, **kwargs):
>         kwargs_Content = kwargs.copy()
>         print(kwargs_Content)
>         kwargs_Content["text"] = "" # important
>         self.notebookContent.tab(self.__ContentTabID(tab_id), option=None, **kwargs_Content)
>         return self.notebookTab.tab(tab_id, option=None, **kwargs)
> 
>     def tabs(self):
>         #return self.notebookContent.tabs()
>         return self.notebookTab.tabs()
> 
>     def enable_traversal(self):
>         self.notebookContent.enable_traversal()
>         self.notebookTab.enable_traversal()

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.