commit
61c5f0cdb1
@ -0,0 +1,3 @@
|
|||||||
|
.vscode/
|
||||||
|
nohup.out
|
||||||
|
data/
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,129 @@
|
|||||||
|
import json
|
||||||
|
import threading
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
import dataHandlerPTT as ptt
|
||||||
|
import generalText as gen
|
||||||
|
from queue import Queue
|
||||||
|
from datetime import datetime
|
||||||
|
from pprint import pprint
|
||||||
|
from flask import Flask, render_template, request, jsonify, send_from_directory, Response, stream_with_context, redirect
|
||||||
|
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
|
||||||
|
|
||||||
|
eventQueue = Queue()
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/stream')
|
||||||
|
def stream():
|
||||||
|
return Response(stream_with_context(eventStream(eventQueue)), mimetype='text/event-stream')
|
||||||
|
|
||||||
|
|
||||||
|
def eventStream(eventQueue):
|
||||||
|
while (True):
|
||||||
|
eventNode = eventQueue.get(True)
|
||||||
|
data = json.dumps(eventNode['data'], indent=4, ensure_ascii=False)
|
||||||
|
data = data.splitlines()
|
||||||
|
data = ['data:' + i for i in data]
|
||||||
|
data = '\n'.join(data)
|
||||||
|
yield "event:{event}\n{data}\n\n".format(event=eventNode['event'], data=data)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/data/<path:path>')
|
||||||
|
def send_data(path):
|
||||||
|
return send_from_directory('data', path)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/generalTxt')
|
||||||
|
def generalTxt():
|
||||||
|
return render_template('generalTxt.html', title="泛用文字視覺化工具")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/post/generalTxt/addText', methods=['POST'])
|
||||||
|
def generalText_addText():
|
||||||
|
text = request.json['text']
|
||||||
|
stopwords = request.json['stopwords']
|
||||||
|
randId = ''.join(random.choices(
|
||||||
|
string.ascii_uppercase + string.ascii_lowercase, k=15))
|
||||||
|
result = gen.processText(randId, text, stopwords)
|
||||||
|
return jsonify(Result={
|
||||||
|
'path': result
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return redirect('/ptt')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/ptt')
|
||||||
|
def pttSententree():
|
||||||
|
return render_template('ptt.html', title="PTT Sententree")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/ptt/keywordFrequency', methods=['POST'])
|
||||||
|
def findKeywordFrequency():
|
||||||
|
print(request.json)
|
||||||
|
content = request.json
|
||||||
|
result = ptt.findKeywordFrequency(content)
|
||||||
|
return jsonify(Result=result)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/dev/updateContent')
|
||||||
|
def updateContent():
|
||||||
|
ptt.loadPostContents()
|
||||||
|
return jsonify(Result={
|
||||||
|
'done': True
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/askProgressHandler', methods=['POST'])
|
||||||
|
def askProgressHandler():
|
||||||
|
key = request.json['key']
|
||||||
|
randId = ''.join(random.choices(
|
||||||
|
string.ascii_uppercase + string.ascii_lowercase, k=15))
|
||||||
|
threading.Thread(target=ptt.progressListener,
|
||||||
|
args=(key, eventQueue, randId,)).start()
|
||||||
|
return jsonify(Result={
|
||||||
|
'id': randId
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/addRequest', methods=['POST'])
|
||||||
|
def addRequest():
|
||||||
|
content = request.json
|
||||||
|
ready = False
|
||||||
|
info = None
|
||||||
|
|
||||||
|
files = ptt.findResult(content)
|
||||||
|
|
||||||
|
info = files
|
||||||
|
ready = True
|
||||||
|
|
||||||
|
key = ptt.calcKey(content['startDate'],
|
||||||
|
content["endDate"], content["keyword"], content["pos"])
|
||||||
|
|
||||||
|
return jsonify(Result={
|
||||||
|
'ready': ready,
|
||||||
|
'info': info,
|
||||||
|
'key': key
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/init", methods=['POST'])
|
||||||
|
def initPage():
|
||||||
|
startDate = datetime.today().replace(day=1).strftime('%Y-%m-%d')
|
||||||
|
endDate = datetime.today().strftime('%Y-%m-%d')
|
||||||
|
files = ptt.getDefault(startDate, endDate)
|
||||||
|
return jsonify(Result={
|
||||||
|
"startDate": startDate,
|
||||||
|
'endDate': endDate,
|
||||||
|
'keyword': '',
|
||||||
|
'info': files
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(debug=False, port=4980, host='0.0.0.0', threaded=True)
|
@ -0,0 +1,339 @@
|
|||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
import jieba
|
||||||
|
import re
|
||||||
|
import csv
|
||||||
|
import json
|
||||||
|
import _pickle as pickle
|
||||||
|
import os
|
||||||
|
import io
|
||||||
|
import jieba
|
||||||
|
import multiprocessing as mp
|
||||||
|
from time import time, sleep
|
||||||
|
from functools import partial
|
||||||
|
from numpy import prod
|
||||||
|
from jieba import posseg
|
||||||
|
from progressbar import ProgressBar
|
||||||
|
from datetime import datetime
|
||||||
|
from PTTData import PTTData
|
||||||
|
|
||||||
|
|
||||||
|
defaultDate = {
|
||||||
|
'startDate': None,
|
||||||
|
'endDate': None
|
||||||
|
}
|
||||||
|
|
||||||
|
postContents = None
|
||||||
|
with open('/home/vis/pttDatabase/PTTData/Gossiping/content/content.pck', 'rb') as f:
|
||||||
|
postContents = pickle.load(f)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
defaultStopWords = []
|
||||||
|
data = PTTData('Gossiping', '/home/vis/pttDatabase/PTTData')
|
||||||
|
|
||||||
|
|
||||||
|
with open('resource/stopWords.txt', 'r', encoding='UTF-8') as file:
|
||||||
|
for word in file.readlines():
|
||||||
|
word = word.strip()
|
||||||
|
defaultStopWords.append(word)
|
||||||
|
|
||||||
|
|
||||||
|
def calcKey(startDate, endDate, keyword, pos):
|
||||||
|
hashKey = str(hex(hash(startDate) + sys.maxsize)[2:]) + \
|
||||||
|
str(hex(hash(endDate) + sys.maxsize)
|
||||||
|
[2:]) + str(hex(hash(keyword) + sys.maxsize)[2:])
|
||||||
|
for key, val in pos.items():
|
||||||
|
hashKey += ('1' if val else '0')
|
||||||
|
return hashKey
|
||||||
|
|
||||||
|
|
||||||
|
def contentProcess(content, text):
|
||||||
|
aid = text[0]
|
||||||
|
text = text[1]
|
||||||
|
if (content['keyword'] != ''):
|
||||||
|
if (content['keyword'] not in text):
|
||||||
|
return None
|
||||||
|
cutted = filterPOS(content, aid)
|
||||||
|
sentenses = []
|
||||||
|
if (content['keyword'] != ''):
|
||||||
|
pos = [i for i, n in enumerate(cutted) if n == content['keyword']]
|
||||||
|
resultPos = []
|
||||||
|
for i in pos:
|
||||||
|
for j in range(i - 9, i + 10):
|
||||||
|
if (j >= 0 and j < len(cutted) and j not in resultPos):
|
||||||
|
resultPos.append(j)
|
||||||
|
lastPos = -1
|
||||||
|
result = []
|
||||||
|
for i in sorted(resultPos):
|
||||||
|
if (i - lastPos != 1 and lastPos != -1):
|
||||||
|
sentenses.append(result)
|
||||||
|
result = []
|
||||||
|
result.append(cutted[i])
|
||||||
|
lastPos = i
|
||||||
|
sentenses.append(result)
|
||||||
|
else:
|
||||||
|
result = []
|
||||||
|
for i in cutted:
|
||||||
|
result.append(i)
|
||||||
|
if (len(result) >= 50):
|
||||||
|
sentenses.append(result.copy())
|
||||||
|
result = []
|
||||||
|
if (result != []):
|
||||||
|
sentenses.append(result)
|
||||||
|
print(sentenses)
|
||||||
|
return sentenses
|
||||||
|
|
||||||
|
|
||||||
|
def filterPOS(content, aid):
|
||||||
|
if (prod(list(content['pos'].values())) == False):
|
||||||
|
pos = content['pos']
|
||||||
|
cuttedWithPOS = data.posseg(aid)
|
||||||
|
startTime = time()
|
||||||
|
cutted = []
|
||||||
|
for i in cuttedWithPOS:
|
||||||
|
if (i.flag[0] == 'n' or i.flag[0] == 'N'):
|
||||||
|
if (pos['noun']):
|
||||||
|
cutted.append(i.word)
|
||||||
|
elif (i.flag[0] == 'v' or (i.flag[0] == 'V' and i.flag != 'Vi')):
|
||||||
|
if (pos['verb']):
|
||||||
|
cutted.append(i.word)
|
||||||
|
elif (i.flag == 'Vi'):
|
||||||
|
if (pos['adj']):
|
||||||
|
cutted.append(i.word)
|
||||||
|
elif (i.flag == 'ADV'):
|
||||||
|
if (pos['adv']):
|
||||||
|
cutted.append(i.word)
|
||||||
|
elif (i.flag == 'r'):
|
||||||
|
if (pos['pron']):
|
||||||
|
cutted.append(i.word)
|
||||||
|
elif (i.flag == 'POST' or i.flag == 'T'):
|
||||||
|
if (pos['aux']):
|
||||||
|
cutted.append(i.word)
|
||||||
|
else:
|
||||||
|
if (pos['other']):
|
||||||
|
if(i.flag != 'eng' and i.flag != 'x' and i.flag != 'm'):
|
||||||
|
cutted.append(i.word)
|
||||||
|
else:
|
||||||
|
if (i.word == content['keyword']):
|
||||||
|
cutted.append(i.word)
|
||||||
|
else:
|
||||||
|
cuttedWithPOS = data.posseg(aid)
|
||||||
|
cutted = [i.word for i in cuttedWithPOS if (
|
||||||
|
i.flag != 'eng' and i.flag != 'x' and i.flag != 'm')]
|
||||||
|
if('stopwords' in content):
|
||||||
|
stopwords = content['stopwords']
|
||||||
|
else:
|
||||||
|
stopwords = defaultStopWords
|
||||||
|
stopped = [i for i in cutted if i not in stopwords]
|
||||||
|
return stopped
|
||||||
|
|
||||||
|
|
||||||
|
def findKeywordFrequency(content):
|
||||||
|
startDate = datetime.strptime(
|
||||||
|
content["startDate"], '%Y-%m-%d').strftime('%Y%m%d') + '000000'
|
||||||
|
endDate = datetime.strptime(
|
||||||
|
content['endDate'], '%Y-%m-%d').strftime('%Y%m%d') + '999999'
|
||||||
|
result = {
|
||||||
|
'wordCount': 0,
|
||||||
|
'postCount': 0
|
||||||
|
}
|
||||||
|
for i in postContents:
|
||||||
|
if (i['date'] > endDate or i['date'] < startDate):
|
||||||
|
continue
|
||||||
|
if (content['globKeyword'] not in i['content']):
|
||||||
|
continue
|
||||||
|
counts = len(re.findall(content['keyword'], i['content']))
|
||||||
|
if (counts > 0):
|
||||||
|
result['wordCount'] += counts
|
||||||
|
result['postCount'] += 1
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def findRange(wordList: list, text: str):
|
||||||
|
top = wordList[0]
|
||||||
|
bot = wordList[-1]
|
||||||
|
mid = wordList[1:-1]
|
||||||
|
pTop = text.find(wordList[0])
|
||||||
|
pBot = text.rfind(wordList[-1])
|
||||||
|
while (True):
|
||||||
|
topTemp = text.find(wordList[0], pTop + 1)
|
||||||
|
if (topTemp == -1):
|
||||||
|
break
|
||||||
|
skip = False
|
||||||
|
for w in mid:
|
||||||
|
if (text.find(w, topTemp, pBot) == -1):
|
||||||
|
skip = True
|
||||||
|
break
|
||||||
|
if (skip):
|
||||||
|
break
|
||||||
|
pTop = topTemp
|
||||||
|
while (True):
|
||||||
|
botTemp = text.rfind(bot, pTop, pBot)
|
||||||
|
if (botTemp == -1):
|
||||||
|
break
|
||||||
|
skip = False
|
||||||
|
for w in mid:
|
||||||
|
if (text.find(w, pTop, botTemp) == -1):
|
||||||
|
skip = True
|
||||||
|
break
|
||||||
|
if (skip):
|
||||||
|
break
|
||||||
|
pBot = botTemp
|
||||||
|
return (pTop, pBot)
|
||||||
|
|
||||||
|
|
||||||
|
def findResult(content):
|
||||||
|
timeStart = time()
|
||||||
|
key = calcKey(content['startDate'],
|
||||||
|
content["endDate"], content["keyword"], content["pos"])
|
||||||
|
startDate = datetime.strptime(
|
||||||
|
content['startDate'], '%Y-%m-%d').strftime('%Y%m%d') + '000000'
|
||||||
|
endDate = datetime.strptime(
|
||||||
|
content['endDate'], '%Y-%m-%d').strftime('%Y%m%d')+'999999'
|
||||||
|
resultPath = 'data/'
|
||||||
|
counter = 0
|
||||||
|
total = len(postContents)
|
||||||
|
result = []
|
||||||
|
result.append(['id', 'text', 'count'])
|
||||||
|
filtered = []
|
||||||
|
titles = {
|
||||||
|
'info': {
|
||||||
|
'keyword': content['keyword'],
|
||||||
|
'count': 0,
|
||||||
|
'posts': 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i in postContents:
|
||||||
|
if (i['date'] > endDate or i['date'] < startDate):
|
||||||
|
continue
|
||||||
|
counter += 1
|
||||||
|
if (content['keyword'] != ''):
|
||||||
|
if (content['keyword'] in i['content']):
|
||||||
|
filtered.append(i)
|
||||||
|
titles['info']['count'] += len(
|
||||||
|
re.findall(content['keyword'], i['content']))
|
||||||
|
|
||||||
|
else:
|
||||||
|
filtered.append(i)
|
||||||
|
titles['info']['posts'] = len(filtered)
|
||||||
|
filtered = [i for i in sorted(
|
||||||
|
filtered, key=lambda x: x['pushes'], reverse=True)[:50]]
|
||||||
|
print('到第一步為止生成花費', int(time()-timeStart), '秒')
|
||||||
|
counter = 0
|
||||||
|
total = len(filtered)
|
||||||
|
sentensesList = []
|
||||||
|
if(os.name == 'posix'):
|
||||||
|
with mp.Pool(mp.cpu_count()) as pool:
|
||||||
|
processes = pool.map_async(
|
||||||
|
partial(contentProcess, content), [(i['aid'], i['content']) for i in filtered])
|
||||||
|
sentensesList = processes.get()
|
||||||
|
else:
|
||||||
|
sentensesList = map(partial(contentProcess, content), [
|
||||||
|
(i['aid'], i['content']) for i in filtered])
|
||||||
|
for index, i in enumerate(filtered):
|
||||||
|
counter += 1
|
||||||
|
sentenses = sentensesList[index]
|
||||||
|
if (sum([len(i) for i in sentenses]) == 0):
|
||||||
|
continue
|
||||||
|
for j in sentenses:
|
||||||
|
cut = findRange(j, i['content'])
|
||||||
|
seq = ' '.join(j)
|
||||||
|
if (seq not in titles):
|
||||||
|
titles[seq] = {
|
||||||
|
'title': i['title'],
|
||||||
|
'url': i['url'],
|
||||||
|
'pushes': i['pushes'],
|
||||||
|
'author': i['author'],
|
||||||
|
'date': datetime.strptime(i['date'], '%Y%m%d%H%M%S').strftime("%a %b %d %H:%M:%S %Y"),
|
||||||
|
'part': i['content'][max(0, cut[0] - 20): min(len(i['content']), cut[1])].replace('\n', '')
|
||||||
|
}
|
||||||
|
result.append([len(result), seq, 1000 + i['pushes']])
|
||||||
|
print('到第二步為止生成花費', int(time()-timeStart), '秒')
|
||||||
|
fileString = io.StringIO()
|
||||||
|
writer = csv.writer(fileString, delimiter='\t')
|
||||||
|
writer.writerows(result)
|
||||||
|
csvString = fileString.getvalue()
|
||||||
|
jsonString = json.dumps(titles, ensure_ascii=False, indent=4)
|
||||||
|
print('tsv', '生成花費', int(time() - timeStart), '秒')
|
||||||
|
return {
|
||||||
|
'tsv': csvString,
|
||||||
|
'json': jsonString,
|
||||||
|
'stopWords': defaultStopWords
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def loadPostContents():
|
||||||
|
global postContents
|
||||||
|
with open('/home/vis/pttDatabase/PTTData/Gossiping/content/content.pck', 'rb') as f:
|
||||||
|
postContents = pickle.load(f)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
def getDefault(startDate, endDate):
|
||||||
|
global defaultDate
|
||||||
|
if (startDate != defaultDate['startDate'] or endDate != defaultDate['endDate']):
|
||||||
|
loadPostContents
|
||||||
|
defaultDate['startDate'] = startDate
|
||||||
|
defaultDate['endDate'] = endDate
|
||||||
|
print('更新預設資料')
|
||||||
|
timeStart = time()
|
||||||
|
resultPath = 'data/'
|
||||||
|
startDate = datetime.strptime(
|
||||||
|
startDate, '%Y-%m-%d').strftime('%Y%m%d') + '000000'
|
||||||
|
endDate = datetime.strptime(
|
||||||
|
endDate, '%Y-%m-%d').strftime('%Y%m%d')+'999999'
|
||||||
|
counter = 0
|
||||||
|
total = len(postContents)
|
||||||
|
result = []
|
||||||
|
result.append(['id', 'text', 'count'])
|
||||||
|
titles = {}
|
||||||
|
titles['info'] = {
|
||||||
|
'keyword': '',
|
||||||
|
'counts': 0,
|
||||||
|
'posts': 0
|
||||||
|
}
|
||||||
|
filtered = []
|
||||||
|
for i in postContents:
|
||||||
|
if (i['date'] > endDate or i['date'] < startDate):
|
||||||
|
continue
|
||||||
|
filtered.append(i)
|
||||||
|
titles['info']['posts'] = len(filtered)
|
||||||
|
filtered = [i for i in sorted(
|
||||||
|
filtered, key=lambda x: x['pushes'], reverse=True)[:50]]
|
||||||
|
counter = 0
|
||||||
|
total = len(postContents)
|
||||||
|
content = {
|
||||||
|
'keyword': '',
|
||||||
|
'pos': {
|
||||||
|
'other': True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i in filtered:
|
||||||
|
counter += 1
|
||||||
|
post = data[i]
|
||||||
|
sentenses = contentProcess(content, (i['aid'], i['content']))
|
||||||
|
for j in sentenses:
|
||||||
|
cut = findRange(j, i['content'])
|
||||||
|
seq = ' '.join(j)
|
||||||
|
if (seq not in titles):
|
||||||
|
titles[seq] = {
|
||||||
|
'title': i['title'],
|
||||||
|
'url': i['url'],
|
||||||
|
'pushes': i['pushes'],
|
||||||
|
'author': i['author'],
|
||||||
|
'date': datetime.strptime(i['date'], '%Y%m%d%H%M%S').strftime("%a %b %d %H:%M:%S %Y"),
|
||||||
|
'part': i['content'][max(0, cut[0] - 20): min(len(i['content']), cut[1])].replace('\n', '')
|
||||||
|
}
|
||||||
|
result.append([len(result), seq, 1000 + i['pushes']])
|
||||||
|
|
||||||
|
fileString = io.StringIO()
|
||||||
|
writer = csv.writer(fileString, delimiter='\t')
|
||||||
|
writer.writerows(result)
|
||||||
|
csvString = fileString.getvalue()
|
||||||
|
jsonString = json.dumps(titles, ensure_ascii=False, indent=4)
|
||||||
|
print('tsv', '生成花費', int(time() - timeStart), '秒')
|
||||||
|
return {
|
||||||
|
'tsv': csvString,
|
||||||
|
'json': jsonString,
|
||||||
|
'stopWords': defaultStopWords
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
import jieba
|
||||||
|
import csv
|
||||||
|
import nltk
|
||||||
|
import re
|
||||||
|
from jieba import posseg
|
||||||
|
from nltk import tokenize
|
||||||
|
from langdetect import detect
|
||||||
|
|
||||||
|
stopWords = []
|
||||||
|
stopWords.append('\n')
|
||||||
|
stopWords.append(' ')
|
||||||
|
|
||||||
|
with open('resource/stopWords.txt', 'r', encoding='UTF-8') as file:
|
||||||
|
for word in file.readlines():
|
||||||
|
word = word.strip()
|
||||||
|
stopWords.append(word)
|
||||||
|
|
||||||
|
|
||||||
|
def filterPOS(text):
|
||||||
|
print(text)
|
||||||
|
cuttedWithPOS = posseg.cut(text)
|
||||||
|
cutted = [i.word for i in cuttedWithPOS if (
|
||||||
|
i.flag != 'eng' and i.flag != 'x' and i.flag != 'm')]
|
||||||
|
stopped = [i for i in cutted]
|
||||||
|
print(stopped)
|
||||||
|
return stopped
|
||||||
|
|
||||||
|
|
||||||
|
def processText(randId, text, stopwords):
|
||||||
|
if(text == ''):
|
||||||
|
return ''
|
||||||
|
lang = detect(text)
|
||||||
|
sentenses = []
|
||||||
|
print(lang)
|
||||||
|
if (lang == 'zh-cn' or lang == 'zh-tw' or lang == 'ko'):
|
||||||
|
splitted = re.split('。|[\n]+', text)
|
||||||
|
print(splitted)
|
||||||
|
cutted = []
|
||||||
|
for i in splitted:
|
||||||
|
cutted.append(filterPOS(i))
|
||||||
|
print(cutted)
|
||||||
|
for i in cutted:
|
||||||
|
result = []
|
||||||
|
for j in i:
|
||||||
|
if (j in stopwords):
|
||||||
|
continue
|
||||||
|
result.append(j)
|
||||||
|
if (len(result) >= 20):
|
||||||
|
sentenses.append(' '.join(result.copy()))
|
||||||
|
result = []
|
||||||
|
if (result != []):
|
||||||
|
sentenses.append(' '.join(result))
|
||||||
|
else:
|
||||||
|
sentenses = []
|
||||||
|
for sentence in tokenize.sent_tokenize(text):
|
||||||
|
words = sentence.lower().split(' ')
|
||||||
|
print([''.join([a for a in w1 if a.isalpha()]) for w1 in words])
|
||||||
|
sentence = ' '.join([w for w in [''.join([a for a in w1 if a.isalpha()]) for w1 in words] if w not in [sw.lower() for sw in stopwords]])
|
||||||
|
sentenses.append(sentence)
|
||||||
|
result = []
|
||||||
|
result.append(['id', 'text', 'count'])
|
||||||
|
for index, sentence in enumerate(sentenses):
|
||||||
|
result.append([index, sentence, 1000])
|
||||||
|
with open('data/' + randId + '.tsv', 'w', newline='', encoding="utf-8") as f:
|
||||||
|
writer = csv.writer(f, delimiter='\t')
|
||||||
|
writer.writerows(result)
|
||||||
|
f.close()
|
||||||
|
return ('data/' + randId + '.tsv')
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -0,0 +1,20 @@
|
|||||||
|
的
|
||||||
|
是
|
||||||
|
在
|
||||||
|
卻
|
||||||
|
也
|
||||||
|
了
|
||||||
|
而
|
||||||
|
要
|
||||||
|
啊
|
||||||
|
阿
|
||||||
|
又
|
||||||
|
有
|
||||||
|
不
|
||||||
|
我
|
||||||
|
都
|
||||||
|
就
|
||||||
|
完整
|
||||||
|
新聞
|
||||||
|
標題
|
||||||
|
內文
|
@ -0,0 +1,316 @@
|
|||||||
|
body {
|
||||||
|
font-family: "Segoe UI", Arial, 'Noto Sans TC', sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-feature-settings: "palt" 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#infoWindow {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
background-color: #FFF;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 400px;
|
||||||
|
height: 250px;
|
||||||
|
border: lightgray;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
z-index: 99;
|
||||||
|
box-shadow: 0px 5px 20px rgba(0, 0, 0, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#titleList {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
background-color: #FFF;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 653px;
|
||||||
|
height: 600px;
|
||||||
|
border: lightgray;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 26px;
|
||||||
|
z-index: 99;
|
||||||
|
box-shadow: 0px 5px 20px rgba(0, 0, 0, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#stopWordEditor {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
background-color: #FFF;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 653px;
|
||||||
|
height: 600px;
|
||||||
|
border: lightgray;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 26px;
|
||||||
|
z-index: 99;
|
||||||
|
box-shadow: 0px 5px 20px rgba(0, 0, 0, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#sweContainer {
|
||||||
|
position: relative;
|
||||||
|
height: 77%;
|
||||||
|
overflow: auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
transition-duration: 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#titleListContainer {
|
||||||
|
position: relative;
|
||||||
|
height: 77%;
|
||||||
|
overflow: auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
transition-duration: 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deleteListElement {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
padding: 12px 16px 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#titleListContainer::-webkit-scrollbar-track {
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#titleListContainer::-webkit-scrollbar {
|
||||||
|
border-radius: 10px;
|
||||||
|
width: 7px;
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#titleListContainer::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: #CCCCCC;
|
||||||
|
}
|
||||||
|
|
||||||
|
li a {
|
||||||
|
display: block;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
background-color: rgba(255, 255, 255, 0.6);
|
||||||
|
animation: fadeIn 0.2s;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
position: fixed;
|
||||||
|
display: flex;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info.hidden {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
animation: fadeOut 0.2s;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeOut {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodeTitle {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(10px, 30px);
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
z-index: 99;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodeTitle.hidden {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nodeTitleContent {
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%);
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#infoText {
|
||||||
|
left: 50%;
|
||||||
|
top: 24%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#infoButtonGroup {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
left: 50%;
|
||||||
|
top: 44%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
align-content: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#vis {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: aliceblue;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 30px;
|
||||||
|
resize: both;
|
||||||
|
padding: 30px;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#heading {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#graph {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#comment {
|
||||||
|
font-size: 12px;
|
||||||
|
color: darkslategray;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="date" i] {
|
||||||
|
align-items: center;
|
||||||
|
display: -webkit-inline-flex;
|
||||||
|
font-family: monospace;
|
||||||
|
padding-inline-start: 1px;
|
||||||
|
cursor: default;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: lightslategray;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#keywordBox {
|
||||||
|
padding: 7px;
|
||||||
|
align-content: center;
|
||||||
|
border-radius: 3px;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: lightslategray;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#advancedArea {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.general-button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #339977;
|
||||||
|
border: none;
|
||||||
|
text-align: center;
|
||||||
|
height: 31px;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
color: white;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#progBar {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
left: 50%;
|
||||||
|
top: 30%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
align-content: center;
|
||||||
|
width: 80%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rawText {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rawTextBox {
|
||||||
|
width: 100%;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.break {
|
||||||
|
flex-basis: 100%;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blink_me {
|
||||||
|
animation: blinker 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blinker {
|
||||||
|
50% {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,162 @@
|
|||||||
|
//download.js v4.2, by dandavis; 2008-2016. [CCBY2] see http://danml.com/download.html for tests/usage
|
||||||
|
// v1 landed a FF+Chrome compat way of downloading strings to local un-named files, upgraded to use a hidden frame and optional mime
|
||||||
|
// v2 added named files via a[download], msSaveBlob, IE (10+) support, and window.URL support for larger+faster saves than dataURLs
|
||||||
|
// v3 added dataURL and Blob Input, bind-toggle arity, and legacy dataURL fallback was improved with force-download mime and base64 support. 3.1 improved safari handling.
|
||||||
|
// v4 adds AMD/UMD, commonJS, and plain browser support
|
||||||
|
// v4.1 adds url download capability via solo URL argument (same domain/CORS only)
|
||||||
|
// v4.2 adds semantic variable names, long (over 2MB) dataURL support, and hidden by default temp anchors
|
||||||
|
// https://github.com/rndme/download
|
||||||
|
|
||||||
|
(function (root, factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as an anonymous module.
|
||||||
|
define([], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node. Does not work with strict CommonJS, but
|
||||||
|
// only CommonJS-like environments that support module.exports,
|
||||||
|
// like Node.
|
||||||
|
module.exports = factory();
|
||||||
|
} else {
|
||||||
|
// Browser globals (root is window)
|
||||||
|
root.download = factory();
|
||||||
|
}
|
||||||
|
}(this, function () {
|
||||||
|
|
||||||
|
return function download(data, strFileName, strMimeType) {
|
||||||
|
|
||||||
|
var self = window, // this script is only for browsers anyway...
|
||||||
|
defaultMime = "application/octet-stream", // this default mime also triggers iframe downloads
|
||||||
|
mimeType = strMimeType || defaultMime,
|
||||||
|
payload = data,
|
||||||
|
url = !strFileName && !strMimeType && payload,
|
||||||
|
anchor = document.createElement("a"),
|
||||||
|
toString = function(a){return String(a);},
|
||||||
|
myBlob = (self.Blob || self.MozBlob || self.WebKitBlob || toString),
|
||||||
|
fileName = strFileName || "download",
|
||||||
|
blob,
|
||||||
|
reader;
|
||||||
|
myBlob= myBlob.call ? myBlob.bind(self) : Blob ;
|
||||||
|
|
||||||
|
if(String(this)==="true"){ //reverse arguments, allowing download.bind(true, "text/xml", "export.xml") to act as a callback
|
||||||
|
payload=[payload, mimeType];
|
||||||
|
mimeType=payload[0];
|
||||||
|
payload=payload[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(url && url.length< 2048){ // if no filename and no mime, assume a url was passed as the only argument
|
||||||
|
fileName = url.split("/").pop().split("?")[0];
|
||||||
|
anchor.href = url; // assign href prop to temp anchor
|
||||||
|
if(anchor.href.indexOf(url) !== -1){ // if the browser determines that it's a potentially valid url path:
|
||||||
|
var ajax=new XMLHttpRequest();
|
||||||
|
ajax.open( "GET", url, true);
|
||||||
|
ajax.responseType = 'blob';
|
||||||
|
ajax.onload= function(e){
|
||||||
|
download(e.target.response, fileName, defaultMime);
|
||||||
|
};
|
||||||
|
setTimeout(function(){ ajax.send();}, 0); // allows setting custom ajax headers using the return:
|
||||||
|
return ajax;
|
||||||
|
} // end if valid url?
|
||||||
|
} // end if url?
|
||||||
|
|
||||||
|
|
||||||
|
//go ahead and download dataURLs right away
|
||||||
|
if(/^data\:[\w+\-]+\/[\w+\-]+[,;]/.test(payload)){
|
||||||
|
|
||||||
|
if(payload.length > (1024*1024*1.999) && myBlob !== toString ){
|
||||||
|
payload=dataUrlToBlob(payload);
|
||||||
|
mimeType=payload.type || defaultMime;
|
||||||
|
}else{
|
||||||
|
return navigator.msSaveBlob ? // IE10 can't do a[download], only Blobs:
|
||||||
|
navigator.msSaveBlob(dataUrlToBlob(payload), fileName) :
|
||||||
|
saver(payload) ; // everyone else can save dataURLs un-processed
|
||||||
|
}
|
||||||
|
|
||||||
|
}//end if dataURL passed?
|
||||||
|
|
||||||
|
blob = payload instanceof myBlob ?
|
||||||
|
payload :
|
||||||
|
new myBlob([payload], {type: mimeType}) ;
|
||||||
|
|
||||||
|
|
||||||
|
function dataUrlToBlob(strUrl) {
|
||||||
|
var parts= strUrl.split(/[:;,]/),
|
||||||
|
type= parts[1],
|
||||||
|
decoder= parts[2] == "base64" ? atob : decodeURIComponent,
|
||||||
|
binData= decoder( parts.pop() ),
|
||||||
|
mx= binData.length,
|
||||||
|
i= 0,
|
||||||
|
uiArr= new Uint8Array(mx);
|
||||||
|
|
||||||
|
for(i;i<mx;++i) uiArr[i]= binData.charCodeAt(i);
|
||||||
|
|
||||||
|
return new myBlob([uiArr], {type: type});
|
||||||
|
}
|
||||||
|
|
||||||
|
function saver(url, winMode){
|
||||||
|
|
||||||
|
if ('download' in anchor) { //html5 A[download]
|
||||||
|
anchor.href = url;
|
||||||
|
anchor.setAttribute("download", fileName);
|
||||||
|
anchor.className = "download-js-link";
|
||||||
|
anchor.innerHTML = "downloading...";
|
||||||
|
anchor.style.display = "none";
|
||||||
|
document.body.appendChild(anchor);
|
||||||
|
setTimeout(function() {
|
||||||
|
anchor.click();
|
||||||
|
document.body.removeChild(anchor);
|
||||||
|
if(winMode===true){setTimeout(function(){ self.URL.revokeObjectURL(anchor.href);}, 250 );}
|
||||||
|
}, 66);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle non-a[download] safari as best we can:
|
||||||
|
if(/(Version)\/(\d+)\.(\d+)(?:\.(\d+))?.*Safari\//.test(navigator.userAgent)) {
|
||||||
|
url=url.replace(/^data:([\w\/\-\+]+)/, defaultMime);
|
||||||
|
if(!window.open(url)){ // popup blocked, offer direct download:
|
||||||
|
if(confirm("Displaying New Document\n\nUse Save As... to download, then click back to return to this page.")){ location.href=url; }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//do iframe dataURL download (old ch+FF):
|
||||||
|
var f = document.createElement("iframe");
|
||||||
|
document.body.appendChild(f);
|
||||||
|
|
||||||
|
if(!winMode){ // force a mime that will download:
|
||||||
|
url="data:"+url.replace(/^data:([\w\/\-\+]+)/, defaultMime);
|
||||||
|
}
|
||||||
|
f.src=url;
|
||||||
|
setTimeout(function(){ document.body.removeChild(f); }, 333);
|
||||||
|
|
||||||
|
}//end saver
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (navigator.msSaveBlob) { // IE10+ : (has Blob, but not a[download] or URL)
|
||||||
|
return navigator.msSaveBlob(blob, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(self.URL){ // simple fast and modern way using Blob and URL:
|
||||||
|
saver(self.URL.createObjectURL(blob), true);
|
||||||
|
}else{
|
||||||
|
// handle non-Blob()+non-URL browsers:
|
||||||
|
if(typeof blob === "string" || blob.constructor===toString ){
|
||||||
|
try{
|
||||||
|
return saver( "data:" + mimeType + ";base64," + self.btoa(blob) );
|
||||||
|
}catch(y){
|
||||||
|
return saver( "data:" + mimeType + "," + encodeURIComponent(blob) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blob but not URL support:
|
||||||
|
reader=new FileReader();
|
||||||
|
reader.onload=function(e){
|
||||||
|
saver(this.result);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}; /* end download() */
|
||||||
|
}));
|
@ -0,0 +1,128 @@
|
|||||||
|
var tsvPath
|
||||||
|
var stopwords = []
|
||||||
|
|
||||||
|
function clearStopWord() {
|
||||||
|
stopwords = []
|
||||||
|
$('#sweContainer').html('')
|
||||||
|
}
|
||||||
|
|
||||||
|
function addStopWord() {
|
||||||
|
newswRaw = $('#newStopWord').val()
|
||||||
|
newswList = newswRaw.split(' ')
|
||||||
|
for (newsw of newswList) {
|
||||||
|
if (newsw != '') {
|
||||||
|
if (stopwords.includes(newsw)) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
stopwords.push(newsw)
|
||||||
|
$('#sweContainer').append($('<li>').attr('class', 'w3-display-container').append($('<span>').append(newsw)).append($('<span>').attr('class', 'w3-button w3-hover-red w3-transparent w3-display-right').click(function(e) {
|
||||||
|
var index = $(this).parent().index()
|
||||||
|
console.log(stopwords[index])
|
||||||
|
stopwords.splice(index, 1)
|
||||||
|
console.log(stopwords)
|
||||||
|
$('#sweContainer li').eq(index).remove()
|
||||||
|
}).append("×")))
|
||||||
|
console.log(document.getElementById('sweContainer').children[stopwords.indexOf(newsw)])
|
||||||
|
}
|
||||||
|
document.getElementById("sweContainer").scrollTop = document.getElementById('sweContainer').children[stopwords.indexOf(newsw)].offsetTop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#newStopWord').val('')
|
||||||
|
}
|
||||||
|
|
||||||
|
function showStopwordEditor() {
|
||||||
|
console.log(stopwords)
|
||||||
|
$(window).unbind('keydown')
|
||||||
|
$(window).keydown(function(event) {
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
addStopWord()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$('#sweContainer').empty()
|
||||||
|
for (word of stopwords) {
|
||||||
|
$('#sweContainer').append($('<li>').attr('class', 'w3-display-container').append($('<span>').append(word)).append($('<span>').attr('class', 'w3-button w3-hover-red w3-transparent w3-display-right').click(function(e) {
|
||||||
|
var index = $(this).parent().index()
|
||||||
|
console.log(stopwords[index])
|
||||||
|
stopwords.splice(index, 1)
|
||||||
|
console.log(stopwords)
|
||||||
|
$('#sweContainer li').eq(index).remove()
|
||||||
|
}).append("×")))
|
||||||
|
}
|
||||||
|
$('#stopWordEditorLayer').removeClass('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideStopWordEditor() {
|
||||||
|
$(window).unbind('keydown')
|
||||||
|
$(window).keydown(function(event) {
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
event.preventDefault()
|
||||||
|
sendRequest()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$('#stopWordEditorLayer').addClass('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
text = $('#rawTextBox').val()
|
||||||
|
$('#rawText').addClass('hidden')
|
||||||
|
$('#toggleTextBox').html('顯示文字輸入區')
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: '/post/generalTxt/addText',
|
||||||
|
data: JSON.stringify({
|
||||||
|
text: text,
|
||||||
|
stopwords: stopwords
|
||||||
|
}),
|
||||||
|
contentType: 'application/json',
|
||||||
|
success: function(data) {
|
||||||
|
tsvPath = data.Result.path
|
||||||
|
destroyCurrentGraph()
|
||||||
|
d3.select('#graph').append('div').attr('id', 'vis')
|
||||||
|
buildSentetree()
|
||||||
|
$('#graph').removeClass('hidden')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSentetree() {
|
||||||
|
console.log("Build.")
|
||||||
|
var model;
|
||||||
|
var tree;
|
||||||
|
var data;
|
||||||
|
const graph = d3.tsv(tsvPath, buildTree);
|
||||||
|
|
||||||
|
function buildTree(error, rawdata) {
|
||||||
|
const data = rawdata.map(d => Object.assign({}, d, { count: +d.count }));
|
||||||
|
model = new SentenTree.SentenTreeBuilder()
|
||||||
|
.tokenize(SentenTree.tokenizer.tokenizeBySpace)
|
||||||
|
.transformToken(token => (/score(d|s)?/.test(token) ? 'score' : token))
|
||||||
|
.buildModel(data, { maxSupportRatio: 1 });
|
||||||
|
tree = new SentenTree.SentenTreeVis('#vis', {
|
||||||
|
fontSize: [15, 40],
|
||||||
|
gapBetweenGraph: 10
|
||||||
|
});
|
||||||
|
tree.data(model.getRenderedGraphs(2))
|
||||||
|
new ResizeSensor(jQuery('#d3kitRoot'), function() {
|
||||||
|
var scale, origin;
|
||||||
|
scale = Math.min(2, ($('#graph').outerWidth()) / ($('#d3kitRoot').outerWidth() + 60))
|
||||||
|
|
||||||
|
$('#vis').css({
|
||||||
|
transform: "scale(" + scale + ")",
|
||||||
|
'transform-origin': 'top left'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyCurrentGraph() {
|
||||||
|
d3.selectAll('#vis').remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchMessageBox() {
|
||||||
|
$('#rawText').toggleClass('hidden')
|
||||||
|
if ($('#rawText').hasClass('hidden')) {
|
||||||
|
$('#toggleTextBox').html('顯示文字輸入區')
|
||||||
|
} else {
|
||||||
|
$('#toggleTextBox').html('隱藏文字輸入區')
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,348 @@
|
|||||||
|
init()
|
||||||
|
var tsvPath = ''
|
||||||
|
var titlePath = ''
|
||||||
|
var defaultStartDate
|
||||||
|
var defaultEndDate
|
||||||
|
var totalPosts
|
||||||
|
var startDate
|
||||||
|
var endDate
|
||||||
|
var wordTitleList
|
||||||
|
var randId
|
||||||
|
var globKeyword = ''
|
||||||
|
var stopwords = []
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: '/init',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(data) {
|
||||||
|
console.log(data)
|
||||||
|
setDate(data.Result.startDate, data.Result.endDate)
|
||||||
|
document.getElementById('keywordBox').value = data.Result.keyword
|
||||||
|
titlePath = data.Result.titlePath
|
||||||
|
tsvString = data.Result.info.tsv
|
||||||
|
defaultStartDate = data.Result.startDate
|
||||||
|
defaultEndDate = data.Result.endDate
|
||||||
|
json = JSON.parse(data.Result.info.json)
|
||||||
|
console.log(json)
|
||||||
|
wordTitleList = json
|
||||||
|
keywordCountString = ''
|
||||||
|
stopwords = data.Result.info.stopWords
|
||||||
|
if (json.info.keyword != '') {
|
||||||
|
keywordCountString = ' 關鍵字出現次數:' + json.info.count
|
||||||
|
}
|
||||||
|
$('#graphInfo').empty()
|
||||||
|
$('#graphInfo').attr('style', 'margin: 10px;').append('總文章數:' + json.info.posts + ',' + keywordCountString)
|
||||||
|
totalPosts = json.info.posts
|
||||||
|
buildSentetree(tsvString)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$(document).ready(function() {
|
||||||
|
$(window).keydown(function(event) {
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
event.preventDefault()
|
||||||
|
sendRequest()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$(window).on('mousemove', function(e) {
|
||||||
|
$('#nodeTitle').css({
|
||||||
|
left: e.pageX,
|
||||||
|
top: e.pageY
|
||||||
|
})
|
||||||
|
})
|
||||||
|
$('#titleListContainer').hover(
|
||||||
|
function() { // Run on hover/mouseenter
|
||||||
|
$(this).css('overflow', 'auto')
|
||||||
|
},
|
||||||
|
function() { // Run on mouseleave
|
||||||
|
$(this).css('overflow', 'hidden')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
$('#titleListLayer').click(function(e) {
|
||||||
|
if ($('#titleListLayer').is(e.target)) {
|
||||||
|
hideTitles()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$('#stopWordEditorLayer').click(function(e) {
|
||||||
|
if ($('#stopWordEditorLayer').is(e.target)) {
|
||||||
|
hideStopWordEditor()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearStopWord() {
|
||||||
|
stopwords = []
|
||||||
|
$('#sweContainer').html('')
|
||||||
|
}
|
||||||
|
|
||||||
|
function addStopWord() {
|
||||||
|
newswRaw = $('#newStopWord').val()
|
||||||
|
newswList = newswRaw.split(' ')
|
||||||
|
for (newsw of newswList) {
|
||||||
|
if (newsw != '') {
|
||||||
|
if (stopwords.includes(newsw)) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
stopwords.push(newsw)
|
||||||
|
$('#sweContainer').append($('<li>').attr('class', 'w3-display-container').append($('<span>').append(newsw)).append($('<span>').attr('class', 'w3-button w3-hover-red w3-transparent w3-display-right').click(function(e) {
|
||||||
|
var index = $(this).parent().index()
|
||||||
|
console.log(stopwords[index])
|
||||||
|
stopwords.splice(index, 1)
|
||||||
|
console.log(stopwords)
|
||||||
|
$('#sweContainer li').eq(index).remove()
|
||||||
|
}).append("×")))
|
||||||
|
console.log(document.getElementById('sweContainer').children[stopwords.indexOf(newsw)])
|
||||||
|
}
|
||||||
|
document.getElementById("sweContainer").scrollTop = document.getElementById('sweContainer').children[stopwords.indexOf(newsw)].offsetTop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#newStopWord').val('')
|
||||||
|
}
|
||||||
|
|
||||||
|
function showStopwordEditor() {
|
||||||
|
console.log(stopwords)
|
||||||
|
$(window).unbind('keydown')
|
||||||
|
$(window).keydown(function(event) {
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
addStopWord()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$('#sweContainer').empty()
|
||||||
|
for (word of stopwords) {
|
||||||
|
$('#sweContainer').append($('<li>').attr('class', 'w3-display-container').append($('<span>').append(word)).append($('<span>').attr('class', 'w3-button w3-hover-red w3-transparent w3-display-right').click(function(e) {
|
||||||
|
var index = $(this).parent().index()
|
||||||
|
console.log(stopwords[index])
|
||||||
|
stopwords.splice(index, 1)
|
||||||
|
console.log(stopwords)
|
||||||
|
$('#sweContainer li').eq(index).remove()
|
||||||
|
}).append("×")))
|
||||||
|
}
|
||||||
|
$('#stopWordEditorLayer').removeClass('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideStopWordEditor() {
|
||||||
|
$(window).unbind('keydown')
|
||||||
|
$(window).keydown(function(event) {
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
event.preventDefault()
|
||||||
|
sendRequest()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$('#stopWordEditorLayer').addClass('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadStopWord() {
|
||||||
|
stopWordString = stopwords.join('\n')
|
||||||
|
download(stopWordString, 'stopwords.txt', 'text/plain')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function hidePopup() {
|
||||||
|
$('#infoWindowLayer').toggleClass('hidden')
|
||||||
|
$('#progressInfo').html('')
|
||||||
|
$('#progBarInner').css('width', 0 + '%')
|
||||||
|
closeEventListner()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDate(_startDate, _endDate) {
|
||||||
|
document.getElementById('startDate').value = _startDate
|
||||||
|
document.getElementById("endDate").value = _endDate
|
||||||
|
startDate = _startDate
|
||||||
|
endDate = _endDate
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProgressing(event) {
|
||||||
|
data = JSON.parse(event.data)
|
||||||
|
$('#progressInfo').html(data.comment)
|
||||||
|
$('#progBarInner').css('width', data.progress + '%')
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProgressFinished(event) {
|
||||||
|
data = JSON.parse(event.data)
|
||||||
|
changeGraph(data)
|
||||||
|
hidePopup()
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeEventListner() {
|
||||||
|
progListener.removeEventListener('progressing' + randId, getProgressing)
|
||||||
|
progListener.removeEventListener('progressFinished' + randId, getProgressFinished)
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendRequest() {
|
||||||
|
content = JSON.stringify({
|
||||||
|
startDate: $('#startDate').val(),
|
||||||
|
endDate: $('#endDate').val(),
|
||||||
|
keyword: $('#keywordBox').val(),
|
||||||
|
stopwords: stopwords,
|
||||||
|
pos: {
|
||||||
|
noun: $('#noun').is(':checked'),
|
||||||
|
verb: $('#verb').is(':checked'),
|
||||||
|
adj: $('#adj').is(':checked'),
|
||||||
|
adv: $('#adv').is(':checked'),
|
||||||
|
pron: $('#pron').is(':checked'),
|
||||||
|
aux: $('#aux').is(':checked'),
|
||||||
|
other: $('#other').is(':checked')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
startDate = $('#startDate').val()
|
||||||
|
endDate = $('#endDate').val()
|
||||||
|
console.log(content)
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: '/addRequest',
|
||||||
|
data: content,
|
||||||
|
contentType: 'application/json',
|
||||||
|
success: function(data) {
|
||||||
|
console.log(data)
|
||||||
|
changeGraph(data.Result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeGraph(data) {
|
||||||
|
console.log(data)
|
||||||
|
tsvString = data.info.tsv
|
||||||
|
json = JSON.parse(data.info.json)
|
||||||
|
globKeyword = json.info.keyword
|
||||||
|
console.log(json)
|
||||||
|
wordTitleList = json
|
||||||
|
keywordCountString = ''
|
||||||
|
if (json.info.keyword != '') {
|
||||||
|
keywordCountString = ', 關鍵字出現次數:' + json.info.count
|
||||||
|
}
|
||||||
|
$('#graphInfo').empty()
|
||||||
|
$('#graphInfo').attr('style', 'margin: 10px;').append('總文章數:' + json.info.posts + keywordCountString)
|
||||||
|
totalPosts = json.info.posts
|
||||||
|
destroyCurrentGraph()
|
||||||
|
d3.select('#graph').append('div').attr('id', 'vis')
|
||||||
|
buildSentetree(tsvString)
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyCurrentGraph() {
|
||||||
|
d3.selectAll('#vis').remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideTitles() {
|
||||||
|
$('#titleListLayer').addClass('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSentetree(tsvString) {
|
||||||
|
console.log("Build.")
|
||||||
|
var model;
|
||||||
|
var tree;
|
||||||
|
var data;
|
||||||
|
if (typeof tsvString === 'undefined') {
|
||||||
|
d3.tsv(tsvPath, buildTree)
|
||||||
|
} else {
|
||||||
|
data = d3.tsvParse(tsvString)
|
||||||
|
buildTree(_, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTree(error, rawdata) {
|
||||||
|
const data = rawdata.map(d => Object.assign({}, d, { count: +d.count }));
|
||||||
|
model = new SentenTree.SentenTreeBuilder()
|
||||||
|
.tokenize(SentenTree.tokenizer.tokenizeBySpace)
|
||||||
|
.transformToken(token => (/score(d|s)?/.test(token) ? 'score' : token))
|
||||||
|
.buildModel(data, {
|
||||||
|
maxSupportRatio: 0.8,
|
||||||
|
minSupportRatio: 0.001
|
||||||
|
});
|
||||||
|
tree = new SentenTree.SentenTreeVis('#vis', {
|
||||||
|
fontSize: [15, 40],
|
||||||
|
gapBetweenGraph: 10
|
||||||
|
});
|
||||||
|
tree.data(model.getRenderedGraphs(2))
|
||||||
|
.on('nodeClick', node => {
|
||||||
|
$("#keywordBox").val(node.data.entity)
|
||||||
|
$('#titleListLayer').removeClass('hidden')
|
||||||
|
seqList = node.data.seq.DBs.map(function(n) {
|
||||||
|
return n.rawText
|
||||||
|
})
|
||||||
|
titleList = []
|
||||||
|
for (s of seqList) {
|
||||||
|
titleTemp = wordTitleList[s]
|
||||||
|
if ((titleList.map(function(n) {
|
||||||
|
return n.title
|
||||||
|
})).indexOf(titleTemp.title) == -1) {
|
||||||
|
titleList.push(titleTemp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(titleList)
|
||||||
|
info = wordTitleList[node.data.entity]
|
||||||
|
$('#titleListKeyword').html(node.data.entity)
|
||||||
|
$('#titleListKeywordInfo').html('')
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: '/ptt/keywordFrequency',
|
||||||
|
data: JSON.stringify({
|
||||||
|
startDate: startDate,
|
||||||
|
endDate: endDate,
|
||||||
|
keyword: node.data.entity,
|
||||||
|
globKeyword: globKeyword
|
||||||
|
}),
|
||||||
|
contentType: 'application/json',
|
||||||
|
success: function(data) {
|
||||||
|
console.log(data)
|
||||||
|
$('#titleListKeywordInfo').html('單詞出現次數:' + data.Result.wordCount + ', 單詞出現的文章數:' + data.Result.postCount + ', 單詞頻率:' + (data.Result.postCount * 100 / totalPosts).toFixed(2) + '%')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$('#titleListContainer').empty()
|
||||||
|
for (i of titleList) {
|
||||||
|
$('#titleListContainer').append(
|
||||||
|
$('<li>').attr('class', 'w3-panel').append(
|
||||||
|
$('<a>').attr('href', i.url).attr('target', '_blank').append(
|
||||||
|
$('<h4>').html(i.title)
|
||||||
|
).append(
|
||||||
|
$('<span>').attr('style', 'margin: 0px 10px').html(i.author)
|
||||||
|
).append(
|
||||||
|
$('<span>').attr('style', 'margin: 0px 10px').html(i.date)
|
||||||
|
).append(
|
||||||
|
$('<span>').attr('style', 'margin: 0px 10px').html('推文數:' + i.pushes)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on('nodeMouseenter', node => {
|
||||||
|
console.log(node)
|
||||||
|
titles = node.data.topEntries.map(function(x) {
|
||||||
|
return wordTitleList[x.rawText]
|
||||||
|
})
|
||||||
|
//console.log(titles)
|
||||||
|
infoStr = ''
|
||||||
|
for (index in titles) {
|
||||||
|
if (index == 0) {
|
||||||
|
infoStr += titles[index].title + '<br>'
|
||||||
|
} else {
|
||||||
|
if (titles[index].title != titles[index - 1].title) {
|
||||||
|
infoStr += titles[index].title + '<br>'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos = titles[index].part.indexOf(node.data.entity)
|
||||||
|
infoStr += '... ' + titles[index].part.slice(Math.max(0, pos - 20), Math.min(titles[index].part.length - 1, pos + 20)) + ' ...<br>'
|
||||||
|
}
|
||||||
|
$(nodeTitleContent).html(infoStr)
|
||||||
|
$('#nodeTitle').removeClass('hidden')
|
||||||
|
tree.highlightNeighbors(node)
|
||||||
|
})
|
||||||
|
.on('nodeMouseleave', node => {
|
||||||
|
$('#nodeTitle').addClass('hidden')
|
||||||
|
tree.clearHighlightNeighbors()
|
||||||
|
}).on('layoutStart', layout => {
|
||||||
|
console.log(layout)
|
||||||
|
}).on('linkMouseenter', link => {
|
||||||
|
console.log(link)
|
||||||
|
})
|
||||||
|
new ResizeSensor(jQuery('#d3kitRoot'), function() {
|
||||||
|
var scale, origin;
|
||||||
|
scale = Math.min(2, ($('#graph').outerWidth()) / ($('#d3kitRoot').outerWidth() + 60))
|
||||||
|
|
||||||
|
$('#vis').css({
|
||||||
|
transform: "scale(" + scale + ")",
|
||||||
|
'transform-origin': 'top left'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../d3-dsv/bin/dsv2json" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../d3-dsv/bin/dsv2json" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
"%_prog%" "%dp0%\..\d3-dsv\bin\dsv2json" %*
|
||||||
|
ENDLOCAL
|
||||||
|
EXIT /b %errorlevel%
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
& "$basedir/node$exe" "$basedir/../d3-dsv/bin/dsv2json" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../d3-dsv/bin/dsv2json" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../d3-dsv/bin/dsv2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../d3-dsv/bin/dsv2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
"%_prog%" "%dp0%\..\d3-dsv\bin\dsv2dsv" %*
|
||||||
|
ENDLOCAL
|
||||||
|
EXIT /b %errorlevel%
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
& "$basedir/node$exe" "$basedir/../d3-dsv/bin/dsv2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../d3-dsv/bin/dsv2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../d3-dsv/bin/dsv2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../d3-dsv/bin/dsv2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
"%_prog%" "%dp0%\..\d3-dsv\bin\dsv2dsv" %*
|
||||||
|
ENDLOCAL
|
||||||
|
EXIT /b %errorlevel%
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
& "$basedir/node$exe" "$basedir/../d3-dsv/bin/dsv2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../d3-dsv/bin/dsv2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../d3-dsv/bin/dsv2json" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../d3-dsv/bin/dsv2json" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
"%_prog%" "%dp0%\..\d3-dsv\bin\dsv2json" %*
|
||||||
|
ENDLOCAL
|
||||||
|
EXIT /b %errorlevel%
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
& "$basedir/node$exe" "$basedir/../d3-dsv/bin/dsv2json" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../d3-dsv/bin/dsv2json" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../d3-dsv/bin/json2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../d3-dsv/bin/json2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
"%_prog%" "%dp0%\..\d3-dsv\bin\json2dsv" %*
|
||||||
|
ENDLOCAL
|
||||||
|
EXIT /b %errorlevel%
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
& "$basedir/node$exe" "$basedir/../d3-dsv/bin/json2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../d3-dsv/bin/json2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../d3-dsv/bin/json2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../d3-dsv/bin/json2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
"%_prog%" "%dp0%\..\d3-dsv\bin\json2dsv" %*
|
||||||
|
ENDLOCAL
|
||||||
|
EXIT /b %errorlevel%
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
& "$basedir/node$exe" "$basedir/../d3-dsv/bin/json2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../d3-dsv/bin/json2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../d3-dsv/bin/json2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../d3-dsv/bin/json2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
"%_prog%" "%dp0%\..\d3-dsv\bin\json2dsv" %*
|
||||||
|
ENDLOCAL
|
||||||
|
EXIT /b %errorlevel%
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
& "$basedir/node$exe" "$basedir/../d3-dsv/bin/json2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../d3-dsv/bin/json2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../d3-dsv/bin/dsv2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../d3-dsv/bin/dsv2dsv" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
"%_prog%" "%dp0%\..\d3-dsv\bin\dsv2dsv" %*
|
||||||
|
ENDLOCAL
|
||||||
|
EXIT /b %errorlevel%
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
& "$basedir/node$exe" "$basedir/../d3-dsv/bin/dsv2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../d3-dsv/bin/dsv2dsv" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||||
|
|
||||||
|
case `uname` in
|
||||||
|
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -x "$basedir/node" ]; then
|
||||||
|
"$basedir/node" "$basedir/../d3-dsv/bin/dsv2json" "$@"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
node "$basedir/../d3-dsv/bin/dsv2json" "$@"
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
exit $ret
|
@ -0,0 +1,17 @@
|
|||||||
|
@ECHO off
|
||||||
|
SETLOCAL
|
||||||
|
CALL :find_dp0
|
||||||
|
|
||||||
|
IF EXIST "%dp0%\node.exe" (
|
||||||
|
SET "_prog=%dp0%\node.exe"
|
||||||
|
) ELSE (
|
||||||
|
SET "_prog=node"
|
||||||
|
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||||
|
)
|
||||||
|
|
||||||
|
"%_prog%" "%dp0%\..\d3-dsv\bin\dsv2json" %*
|
||||||
|
ENDLOCAL
|
||||||
|
EXIT /b %errorlevel%
|
||||||
|
:find_dp0
|
||||||
|
SET dp0=%~dp0
|
||||||
|
EXIT /b
|
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
|
||||||
|
$exe=""
|
||||||
|
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||||
|
# Fix case when both the Windows and Linux builds of Node
|
||||||
|
# are installed in the same directory
|
||||||
|
$exe=".exe"
|
||||||
|
}
|
||||||
|
$ret=0
|
||||||
|
if (Test-Path "$basedir/node$exe") {
|
||||||
|
& "$basedir/node$exe" "$basedir/../d3-dsv/bin/dsv2json" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
} else {
|
||||||
|
& "node$exe" "$basedir/../d3-dsv/bin/dsv2json" $args
|
||||||
|
$ret=$LASTEXITCODE
|
||||||
|
}
|
||||||
|
exit $ret
|
@ -0,0 +1,22 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||||
|
|
||||||
|
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.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"_from": "commander@2",
|
||||||
|
"_id": "commander@2.20.3",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
|
"_location": "/commander",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "range",
|
||||||
|
"registry": true,
|
||||||
|
"raw": "commander@2",
|
||||||
|
"name": "commander",
|
||||||
|
"escapedName": "commander",
|
||||||
|
"rawSpec": "2",
|
||||||
|
"saveSpec": null,
|
||||||
|
"fetchSpec": "2"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"/d3-dsv"
|
||||||
|
],
|
||||||
|
"_resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
|
"_shasum": "fd485e84c03eb4881c20722ba48035e8531aeb33",
|
||||||
|
"_spec": "commander@2",
|
||||||
|
"_where": "C:\\Users\\a5640\\OneDrive - National ChengChi University\\programming\\Python\\flask\\sententree\\static\\node_modules\\d3-dsv",
|
||||||
|
"author": {
|
||||||
|
"name": "TJ Holowaychuk",
|
||||||
|
"email": "tj@vision-media.ca"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/tj/commander.js/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"dependencies": {},
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "the complete solution for node.js command-line programs",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^12.7.8",
|
||||||
|
"eslint": "^6.4.0",
|
||||||
|
"should": "^13.2.3",
|
||||||
|
"sinon": "^7.5.0",
|
||||||
|
"standard": "^14.3.1",
|
||||||
|
"ts-node": "^8.4.1",
|
||||||
|
"typescript": "^3.6.3"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"index.js",
|
||||||
|
"typings/index.d.ts"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/tj/commander.js#readme",
|
||||||
|
"keywords": [
|
||||||
|
"commander",
|
||||||
|
"command",
|
||||||
|
"option",
|
||||||
|
"parser"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "index",
|
||||||
|
"name": "commander",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/tj/commander.js.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint index.js",
|
||||||
|
"test": "node test/run.js && npm run test-typings",
|
||||||
|
"test-typings": "tsc -p tsconfig.json"
|
||||||
|
},
|
||||||
|
"typings": "typings/index.d.ts",
|
||||||
|
"version": "2.20.3"
|
||||||
|
}
|
@ -0,0 +1,310 @@
|
|||||||
|
// Type definitions for commander 2.11
|
||||||
|
// Project: https://github.com/visionmedia/commander.js
|
||||||
|
// Definitions by: Alan Agius <https://github.com/alan-agius4>, Marcelo Dezem <https://github.com/mdezem>, vvakame <https://github.com/vvakame>, Jules Randolph <https://github.com/sveinburne>
|
||||||
|
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||||
|
|
||||||
|
declare namespace local {
|
||||||
|
|
||||||
|
class Option {
|
||||||
|
flags: string;
|
||||||
|
required: boolean;
|
||||||
|
optional: boolean;
|
||||||
|
bool: boolean;
|
||||||
|
short?: string;
|
||||||
|
long: string;
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new `Option` with the given `flags` and `description`.
|
||||||
|
*
|
||||||
|
* @param {string} flags
|
||||||
|
* @param {string} [description]
|
||||||
|
*/
|
||||||
|
constructor(flags: string, description?: string);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Command extends NodeJS.EventEmitter {
|
||||||
|
[key: string]: any;
|
||||||
|
|
||||||
|
args: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new `Command`.
|
||||||
|
*
|
||||||
|
* @param {string} [name]
|
||||||
|
*/
|
||||||
|
constructor(name?: string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the program version to `str`.
|
||||||
|
*
|
||||||
|
* This method auto-registers the "-V, --version" flag
|
||||||
|
* which will print the version number when passed.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @param {string} [flags]
|
||||||
|
* @returns {Command} for chaining
|
||||||
|
*/
|
||||||
|
version(str: string, flags?: string): Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add command `name`.
|
||||||
|
*
|
||||||
|
* The `.action()` callback is invoked when the
|
||||||
|
* command `name` is specified via __ARGV__,
|
||||||
|
* and the remaining arguments are applied to the
|
||||||
|
* function for access.
|
||||||
|
*
|
||||||
|
* When the `name` is "*" an un-matched command
|
||||||
|
* will be passed as the first arg, followed by
|
||||||
|
* the rest of __ARGV__ remaining.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* program
|
||||||
|
* .version('0.0.1')
|
||||||
|
* .option('-C, --chdir <path>', 'change the working directory')
|
||||||
|
* .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
|
||||||
|
* .option('-T, --no-tests', 'ignore test hook')
|
||||||
|
*
|
||||||
|
* program
|
||||||
|
* .command('setup')
|
||||||
|
* .description('run remote setup commands')
|
||||||
|
* .action(function() {
|
||||||
|
* console.log('setup');
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* program
|
||||||
|
* .command('exec <cmd>')
|
||||||
|
* .description('run the given remote command')
|
||||||
|
* .action(function(cmd) {
|
||||||
|
* console.log('exec "%s"', cmd);
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* program
|
||||||
|
* .command('teardown <dir> [otherDirs...]')
|
||||||
|
* .description('run teardown commands')
|
||||||
|
* .action(function(dir, otherDirs) {
|
||||||
|
* console.log('dir "%s"', dir);
|
||||||
|
* if (otherDirs) {
|
||||||
|
* otherDirs.forEach(function (oDir) {
|
||||||
|
* console.log('dir "%s"', oDir);
|
||||||
|
* });
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* program
|
||||||
|
* .command('*')
|
||||||
|
* .description('deploy the given env')
|
||||||
|
* .action(function(env) {
|
||||||
|
* console.log('deploying "%s"', env);
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* program.parse(process.argv);
|
||||||
|
*
|
||||||
|
* @param {string} name
|
||||||
|
* @param {string} [desc] for git-style sub-commands
|
||||||
|
* @param {CommandOptions} [opts] command options
|
||||||
|
* @returns {Command} the new command
|
||||||
|
*/
|
||||||
|
command(name: string, desc?: string, opts?: commander.CommandOptions): Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define argument syntax for the top-level command.
|
||||||
|
*
|
||||||
|
* @param {string} desc
|
||||||
|
* @returns {Command} for chaining
|
||||||
|
*/
|
||||||
|
arguments(desc: string): Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse expected `args`.
|
||||||
|
*
|
||||||
|
* For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
|
||||||
|
*
|
||||||
|
* @param {string[]} args
|
||||||
|
* @returns {Command} for chaining
|
||||||
|
*/
|
||||||
|
parseExpectedArgs(args: string[]): Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register callback `fn` for the command.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* program
|
||||||
|
* .command('help')
|
||||||
|
* .description('display verbose help')
|
||||||
|
* .action(function() {
|
||||||
|
* // output help here
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param {(...args: any[]) => void} fn
|
||||||
|
* @returns {Command} for chaining
|
||||||
|
*/
|
||||||
|
action(fn: (...args: any[]) => void): Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define option with `flags`, `description` and optional
|
||||||
|
* coercion `fn`.
|
||||||
|
*
|
||||||
|
* The `flags` string should contain both the short and long flags,
|
||||||
|
* separated by comma, a pipe or space. The following are all valid
|
||||||
|
* all will output this way when `--help` is used.
|
||||||
|
*
|
||||||
|
* "-p, --pepper"
|
||||||
|
* "-p|--pepper"
|
||||||
|
* "-p --pepper"
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // simple boolean defaulting to false
|
||||||
|
* program.option('-p, --pepper', 'add pepper');
|
||||||
|
*
|
||||||
|
* --pepper
|
||||||
|
* program.pepper
|
||||||
|
* // => Boolean
|
||||||
|
*
|
||||||
|
* // simple boolean defaulting to true
|
||||||
|
* program.option('-C, --no-cheese', 'remove cheese');
|
||||||
|
*
|
||||||
|
* program.cheese
|
||||||
|
* // => true
|
||||||
|
*
|
||||||
|
* --no-cheese
|
||||||
|
* program.cheese
|
||||||
|
* // => false
|
||||||
|
*
|
||||||
|
* // required argument
|
||||||
|
* program.option('-C, --chdir <path>', 'change the working directory');
|
||||||
|
*
|
||||||
|
* --chdir /tmp
|
||||||
|
* program.chdir
|
||||||
|
* // => "/tmp"
|
||||||
|
*
|
||||||
|
* // optional argument
|
||||||
|
* program.option('-c, --cheese [type]', 'add cheese [marble]');
|
||||||
|
*
|
||||||
|
* @param {string} flags
|
||||||
|
* @param {string} [description]
|
||||||
|
* @param {((arg1: any, arg2: any) => void) | RegExp} [fn] function or default
|
||||||
|
* @param {*} [defaultValue]
|
||||||
|
* @returns {Command} for chaining
|
||||||
|
*/
|
||||||
|
option(flags: string, description?: string, fn?: ((arg1: any, arg2: any) => void) | RegExp, defaultValue?: any): Command;
|
||||||
|
option(flags: string, description?: string, defaultValue?: any): Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow unknown options on the command line.
|
||||||
|
*
|
||||||
|
* @param {boolean} [arg] if `true` or omitted, no error will be thrown for unknown options.
|
||||||
|
* @returns {Command} for chaining
|
||||||
|
*/
|
||||||
|
allowUnknownOption(arg?: boolean): Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse `argv`, settings options and invoking commands when defined.
|
||||||
|
*
|
||||||
|
* @param {string[]} argv
|
||||||
|
* @returns {Command} for chaining
|
||||||
|
*/
|
||||||
|
parse(argv: string[]): Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse options from `argv` returning `argv` void of these options.
|
||||||
|
*
|
||||||
|
* @param {string[]} argv
|
||||||
|
* @returns {ParseOptionsResult}
|
||||||
|
*/
|
||||||
|
parseOptions(argv: string[]): commander.ParseOptionsResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an object containing options as key-value pairs
|
||||||
|
*
|
||||||
|
* @returns {{[key: string]: any}}
|
||||||
|
*/
|
||||||
|
opts(): { [key: string]: any };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the description to `str`.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @param {{[argName: string]: string}} argsDescription
|
||||||
|
* @return {(Command | string)}
|
||||||
|
*/
|
||||||
|
description(str: string, argsDescription?: {[argName: string]: string}): Command;
|
||||||
|
description(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an alias for the command.
|
||||||
|
*
|
||||||
|
* @param {string} alias
|
||||||
|
* @return {(Command | string)}
|
||||||
|
*/
|
||||||
|
alias(alias: string): Command;
|
||||||
|
alias(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set or get the command usage.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @return {(Command | string)}
|
||||||
|
*/
|
||||||
|
usage(str: string): Command;
|
||||||
|
usage(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the name of the command.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @return {Command}
|
||||||
|
*/
|
||||||
|
name(str: string): Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the command.
|
||||||
|
*
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
name(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output help information for this command.
|
||||||
|
*
|
||||||
|
* @param {(str: string) => string} [cb]
|
||||||
|
*/
|
||||||
|
outputHelp(cb?: (str: string) => string): void;
|
||||||
|
|
||||||
|
/** Output help information and exit.
|
||||||
|
*
|
||||||
|
* @param {(str: string) => string} [cb]
|
||||||
|
*/
|
||||||
|
help(cb?: (str: string) => string): never;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
declare namespace commander {
|
||||||
|
|
||||||
|
type Command = local.Command
|
||||||
|
|
||||||
|
type Option = local.Option
|
||||||
|
|
||||||
|
interface CommandOptions {
|
||||||
|
noHelp?: boolean;
|
||||||
|
isDefault?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParseOptionsResult {
|
||||||
|
args: string[];
|
||||||
|
unknown: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CommanderStatic extends Command {
|
||||||
|
Command: typeof local.Command;
|
||||||
|
Option: typeof local.Option;
|
||||||
|
CommandOptions: CommandOptions;
|
||||||
|
ParseOptionsResult: ParseOptionsResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const commander: commander.CommanderStatic;
|
||||||
|
export = commander;
|
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
github: marcj
|
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2013 Marc J. Schmidt
|
||||||
|
|
||||||
|
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.
|
@ -0,0 +1,112 @@
|
|||||||
|
# CSS Element Queries
|
||||||
|
|
||||||
|
|
||||||
|
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/marcj/css-element-queries?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
|
|
||||||
|
Element Queries is a polyfill adding support for element based media-queries to all new browsers (incl. IE7+).
|
||||||
|
It allows not only to define media-queries based on window-size but also adds 'media-queries' functionality depending on element (any selector supported)
|
||||||
|
size while not causing performance lags due to event based implementation.
|
||||||
|
|
||||||
|
It's a proof-of-concept event-based CSS element dimension query with valid CSS selector syntax.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
- no performance issues since it listens only on size changes of elements that have element query rules defined through css. Other element query polifills only listen on `window.onresize` which causes performance issues and allows only to detect changes via window.resize event and not inside layout changes like css3 animation, :hover, DOM changes etc.
|
||||||
|
- no interval/timeout detection. Truly event-based through integrated ResizeSensor class.
|
||||||
|
- automatically discovers new DOM elements. No need to call javascript manually.
|
||||||
|
- no CSS modifications. Valid CSS Syntax
|
||||||
|
- all CSS selectors available. Uses regular attribute selector. No need to write rules in HTML/JS.
|
||||||
|
- supports and tested in webkit, gecko and IE(10+)
|
||||||
|
- `min-width`, `min-height`, `max-width` and `max-height` are supported so far
|
||||||
|
- works with any layout modifications: HTML (innerHTML etc), inline styles, DOM mutation, CSS3 transitions, fluid layout changes (also percent changes), pseudo classes (:hover etc.), window resizes and more
|
||||||
|
- no Javascript-Framework dependency (works with jQuery, Mootools, etc.)
|
||||||
|
- Works beautiful for responsive images without FOUC
|
||||||
|
|
||||||
|
More demos and information: http://marcj.github.io/css-element-queries/
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Element Query
|
||||||
|
|
||||||
|
```css
|
||||||
|
.widget-name h2 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-name[min-width~="400px"] h2 {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-name[min-width~="600px"] h2 {
|
||||||
|
padding: 55px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-name[min-width~="700px"] h2 {
|
||||||
|
font-size: 34px;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
As you can see we use the `~=` [attribute selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors).
|
||||||
|
Since this css-element-queries polyfill adds new element attributes on the DOM element
|
||||||
|
(`<div class="widget-name" min-width="400px 700px"></div>`) depending on your actual CSS and element's dimension,
|
||||||
|
you should always use this attribute selector (especially if you have several element query rules on the same element).
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="widget-name">
|
||||||
|
<h2>Element responsiveness FTW!</h2>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Responsive image
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div data-responsive-image>
|
||||||
|
<img data-src="http://placehold.it/350x150"/>
|
||||||
|
<img min-width="350" data-src="http://placehold.it/700x300"/>
|
||||||
|
<img min-width="700" data-src="http://placehold.it/1400x600"/>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Include the javascript files at the bottom and you're good to go. No custom javascript calls needed.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script src="src/ResizeSensor.js"></script>
|
||||||
|
<script src="src/ElementQueries.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
## See it in action:
|
||||||
|
|
||||||
|
Here live http://marcj.github.io/css-element-queries/.
|
||||||
|
|
||||||
|
![Demo](http://marcj.github.io/css-element-queries/images/css-element-queries-demo.gif)
|
||||||
|
|
||||||
|
|
||||||
|
## Module Loader
|
||||||
|
|
||||||
|
If you're using a module loader you need to trigger the event listening or initialization yourself:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var ElementQueries = require('css-element-queries/src/ElementQueries');
|
||||||
|
|
||||||
|
//attaches to DOMLoadContent
|
||||||
|
ElementQueries.listen();
|
||||||
|
|
||||||
|
//or if you want to trigger it yourself.
|
||||||
|
// Parse all available CSS and attach ResizeSensor to those elements which have rules attached
|
||||||
|
// (make sure this is called after 'load' event, because CSS files are not ready when domReady is fired.
|
||||||
|
ElementQueries.init();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
|
||||||
|
- So far does not work on `img` and other elements that can't contain other elements. Wrapping with a `div` works fine though (See demo).
|
||||||
|
- Adds additional hidden elements into selected target element and forces target element to be relative or absolute.
|
||||||
|
- Local stylesheets do not work (using `file://` protocol).
|
||||||
|
- If you have rules on an element that has a css animation, also add `element-queries`. E.g. `.widget-name { animation: 2sec my-animation, 1s element-queries;}`. We use this to detect new added DOM elements automatically.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT license. Copyright [Marc J. Schmidt](https://twitter.com/MarcJSchmidt).
|
@ -0,0 +1,2 @@
|
|||||||
|
export { ResizeSensor, ResizeSensorCallback } from "./src/ResizeSensor";
|
||||||
|
export { ElementQueries } from './src/ElementQueries';
|
@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
ResizeSensor: require('./src/ResizeSensor'),
|
||||||
|
ElementQueries: require('./src/ElementQueries')
|
||||||
|
};
|
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"_from": "css-element-queries",
|
||||||
|
"_id": "css-element-queries@1.2.3",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-QK9uovYmKTsV2GXWQiMOByVNrLn2qz6m3P7vWpOR4IdD6I3iXoDw5qtgJEN3Xq7gIbdHVKvzHjdAtcl+4Arc4Q==",
|
||||||
|
"_location": "/css-element-queries",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "tag",
|
||||||
|
"registry": true,
|
||||||
|
"raw": "css-element-queries",
|
||||||
|
"name": "css-element-queries",
|
||||||
|
"escapedName": "css-element-queries",
|
||||||
|
"rawSpec": "",
|
||||||
|
"saveSpec": null,
|
||||||
|
"fetchSpec": "latest"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"#USER",
|
||||||
|
"/"
|
||||||
|
],
|
||||||
|
"_resolved": "https://registry.npmjs.org/css-element-queries/-/css-element-queries-1.2.3.tgz",
|
||||||
|
"_shasum": "e14940b1fcd4bf0da60ea4145d05742d7172e516",
|
||||||
|
"_spec": "css-element-queries",
|
||||||
|
"_where": "C:\\Users\\a5640\\OneDrive - National ChengChi University\\programming\\Python\\flask\\sententree\\static",
|
||||||
|
"author": {
|
||||||
|
"name": "Marc J. Schmidt"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/marcj/css-element-queries/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "CSS-Element-Queries Polyfill. Proof-of-concept for high-speed element dimension/media queries in valid css.",
|
||||||
|
"devDependencies": {
|
||||||
|
"grunt": "^0.4.5",
|
||||||
|
"grunt-bump": "^0.3.1"
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/marcj/css-element-queries",
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "index.js",
|
||||||
|
"name": "css-element-queries",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+ssh://git@github.com/marcj/css-element-queries.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"typings": "css-element-queries.d.ts",
|
||||||
|
"version": "1.2.3"
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
export declare class ElementQueries {
|
||||||
|
/**
|
||||||
|
* Attaches to DOMLoadContent
|
||||||
|
*/
|
||||||
|
static listen(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses all available CSS and attach ResizeSensor to those elements which have rules attached.
|
||||||
|
* Make sure this is called after 'load' event, because CSS files are not ready when domReady is fired.
|
||||||
|
*/
|
||||||
|
static init(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ElementQueries;
|
@ -0,0 +1,530 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright Marc J. Schmidt. See the LICENSE file at the top-level
|
||||||
|
* directory of this distribution and at
|
||||||
|
* https://github.com/marcj/css-element-queries/blob/master/LICENSE.
|
||||||
|
*/
|
||||||
|
(function (root, factory) {
|
||||||
|
if (typeof define === "function" && define.amd) {
|
||||||
|
define(['./ResizeSensor.js'], factory);
|
||||||
|
} else if (typeof exports === "object") {
|
||||||
|
module.exports = factory(require('./ResizeSensor.js'));
|
||||||
|
} else {
|
||||||
|
root.ElementQueries = factory(root.ResizeSensor);
|
||||||
|
root.ElementQueries.listen();
|
||||||
|
}
|
||||||
|
}(typeof window !== 'undefined' ? window : this, function (ResizeSensor) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {Function}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
var ElementQueries = function () {
|
||||||
|
//<style> element with our dynamically created styles
|
||||||
|
var cssStyleElement;
|
||||||
|
|
||||||
|
//all rules found for element queries
|
||||||
|
var allQueries = {};
|
||||||
|
|
||||||
|
//association map to identify which selector belongs to a element from the animationstart event.
|
||||||
|
var idToSelectorMapping = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param element
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
function getEmSize(element) {
|
||||||
|
if (!element) {
|
||||||
|
element = document.documentElement;
|
||||||
|
}
|
||||||
|
var fontSize = window.getComputedStyle(element, null).fontSize;
|
||||||
|
return parseFloat(fontSize) || 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get element size
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @returns {Object} {width, height}
|
||||||
|
*/
|
||||||
|
function getElementSize(element) {
|
||||||
|
if (!element.getBoundingClientRect) {
|
||||||
|
return {
|
||||||
|
width: element.offsetWidth,
|
||||||
|
height: element.offsetHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rect = element.getBoundingClientRect();
|
||||||
|
return {
|
||||||
|
width: Math.round(rect.width),
|
||||||
|
height: Math.round(rect.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @copyright https://github.com/Mr0grog/element-query/blob/master/LICENSE
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @param {*} value
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
function convertToPx(element, value) {
|
||||||
|
var numbers = value.split(/\d/);
|
||||||
|
var units = numbers[numbers.length - 1];
|
||||||
|
value = parseFloat(value);
|
||||||
|
switch (units) {
|
||||||
|
case "px":
|
||||||
|
return value;
|
||||||
|
case "em":
|
||||||
|
return value * getEmSize(element);
|
||||||
|
case "rem":
|
||||||
|
return value * getEmSize();
|
||||||
|
// Viewport units!
|
||||||
|
// According to http://quirksmode.org/mobile/tableViewport.html
|
||||||
|
// documentElement.clientWidth/Height gets us the most reliable info
|
||||||
|
case "vw":
|
||||||
|
return value * document.documentElement.clientWidth / 100;
|
||||||
|
case "vh":
|
||||||
|
return value * document.documentElement.clientHeight / 100;
|
||||||
|
case "vmin":
|
||||||
|
case "vmax":
|
||||||
|
var vw = document.documentElement.clientWidth / 100;
|
||||||
|
var vh = document.documentElement.clientHeight / 100;
|
||||||
|
var chooser = Math[units === "vmin" ? "min" : "max"];
|
||||||
|
return value * chooser(vw, vh);
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
// for now, not supporting physical units (since they are just a set number of px)
|
||||||
|
// or ex/ch (getting accurate measurements is hard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @param {String} id
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SetupInformation(element, id) {
|
||||||
|
this.element = element;
|
||||||
|
var key, option, elementSize, value, actualValue, attrValues, attrValue, attrName;
|
||||||
|
|
||||||
|
var attributes = ['min-width', 'min-height', 'max-width', 'max-height'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the computed width/height and sets to min/max- attribute.
|
||||||
|
*/
|
||||||
|
this.call = function () {
|
||||||
|
// extract current dimensions
|
||||||
|
elementSize = getElementSize(this.element);
|
||||||
|
|
||||||
|
attrValues = {};
|
||||||
|
|
||||||
|
for (key in allQueries[id]) {
|
||||||
|
if (!allQueries[id].hasOwnProperty(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
option = allQueries[id][key];
|
||||||
|
|
||||||
|
value = convertToPx(this.element, option.value);
|
||||||
|
|
||||||
|
actualValue = option.property === 'width' ? elementSize.width : elementSize.height;
|
||||||
|
attrName = option.mode + '-' + option.property;
|
||||||
|
attrValue = '';
|
||||||
|
|
||||||
|
if (option.mode === 'min' && actualValue >= value) {
|
||||||
|
attrValue += option.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option.mode === 'max' && actualValue <= value) {
|
||||||
|
attrValue += option.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!attrValues[attrName]) attrValues[attrName] = '';
|
||||||
|
if (attrValue && -1 === (' ' + attrValues[attrName] + ' ').indexOf(' ' + attrValue + ' ')) {
|
||||||
|
attrValues[attrName] += ' ' + attrValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var k in attributes) {
|
||||||
|
if (!attributes.hasOwnProperty(k)) continue;
|
||||||
|
|
||||||
|
if (attrValues[attributes[k]]) {
|
||||||
|
this.element.setAttribute(attributes[k], attrValues[attributes[k]].substr(1));
|
||||||
|
} else {
|
||||||
|
this.element.removeAttribute(attributes[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @param {Object} id
|
||||||
|
*/
|
||||||
|
function setupElement(element, id) {
|
||||||
|
if (!element.elementQueriesSetupInformation) {
|
||||||
|
element.elementQueriesSetupInformation = new SetupInformation(element, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!element.elementQueriesSensor) {
|
||||||
|
element.elementQueriesSensor = new ResizeSensor(element, function () {
|
||||||
|
element.elementQueriesSetupInformation.call();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores rules to the selector that should be applied once resized.
|
||||||
|
*
|
||||||
|
* @param {String} selector
|
||||||
|
* @param {String} mode min|max
|
||||||
|
* @param {String} property width|height
|
||||||
|
* @param {String} value
|
||||||
|
*/
|
||||||
|
function queueQuery(selector, mode, property, value) {
|
||||||
|
if (typeof(allQueries[selector]) === 'undefined') {
|
||||||
|
allQueries[selector] = [];
|
||||||
|
// add animation to trigger animationstart event, so we know exactly when a element appears in the DOM
|
||||||
|
|
||||||
|
var id = idToSelectorMapping.length;
|
||||||
|
cssStyleElement.innerHTML += '\n' + selector + ' {animation: 0.1s element-queries;}';
|
||||||
|
cssStyleElement.innerHTML += '\n' + selector + ' > .resize-sensor {min-width: '+id+'px;}';
|
||||||
|
idToSelectorMapping.push(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
allQueries[selector].push({
|
||||||
|
mode: mode,
|
||||||
|
property: property,
|
||||||
|
value: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getQuery(container) {
|
||||||
|
var query;
|
||||||
|
if (document.querySelectorAll) query = (container) ? container.querySelectorAll.bind(container) : document.querySelectorAll.bind(document);
|
||||||
|
if (!query && 'undefined' !== typeof $$) query = $$;
|
||||||
|
if (!query && 'undefined' !== typeof jQuery) query = jQuery;
|
||||||
|
|
||||||
|
if (!query) {
|
||||||
|
throw 'No document.querySelectorAll, jQuery or Mootools\'s $$ found.';
|
||||||
|
}
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If animationStart didn't catch a new element in the DOM, we can manually search for it
|
||||||
|
*/
|
||||||
|
function findElementQueriesElements(container) {
|
||||||
|
var query = getQuery(container);
|
||||||
|
|
||||||
|
for (var selector in allQueries) if (allQueries.hasOwnProperty(selector)) {
|
||||||
|
// find all elements based on the extract query selector from the element query rule
|
||||||
|
var elements = query(selector, container);
|
||||||
|
|
||||||
|
for (var i = 0, j = elements.length; i < j; i++) {
|
||||||
|
setupElement(elements[i], selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
*/
|
||||||
|
function attachResponsiveImage(element) {
|
||||||
|
var children = [];
|
||||||
|
var rules = [];
|
||||||
|
var sources = [];
|
||||||
|
var defaultImageId = 0;
|
||||||
|
var lastActiveImage = -1;
|
||||||
|
var loadedImages = [];
|
||||||
|
|
||||||
|
for (var i in element.children) {
|
||||||
|
if (!element.children.hasOwnProperty(i)) continue;
|
||||||
|
|
||||||
|
if (element.children[i].tagName && element.children[i].tagName.toLowerCase() === 'img') {
|
||||||
|
children.push(element.children[i]);
|
||||||
|
|
||||||
|
var minWidth = element.children[i].getAttribute('min-width') || element.children[i].getAttribute('data-min-width');
|
||||||
|
//var minHeight = element.children[i].getAttribute('min-height') || element.children[i].getAttribute('data-min-height');
|
||||||
|
var src = element.children[i].getAttribute('data-src') || element.children[i].getAttribute('url');
|
||||||
|
|
||||||
|
sources.push(src);
|
||||||
|
|
||||||
|
var rule = {
|
||||||
|
minWidth: minWidth
|
||||||
|
};
|
||||||
|
|
||||||
|
rules.push(rule);
|
||||||
|
|
||||||
|
if (!minWidth) {
|
||||||
|
defaultImageId = children.length - 1;
|
||||||
|
element.children[i].style.display = 'block';
|
||||||
|
} else {
|
||||||
|
element.children[i].style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastActiveImage = defaultImageId;
|
||||||
|
|
||||||
|
function check() {
|
||||||
|
var imageToDisplay = false, i;
|
||||||
|
|
||||||
|
for (i in children) {
|
||||||
|
if (!children.hasOwnProperty(i)) continue;
|
||||||
|
|
||||||
|
if (rules[i].minWidth) {
|
||||||
|
if (element.offsetWidth > rules[i].minWidth) {
|
||||||
|
imageToDisplay = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!imageToDisplay) {
|
||||||
|
//no rule matched, show default
|
||||||
|
imageToDisplay = defaultImageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastActiveImage !== imageToDisplay) {
|
||||||
|
//image change
|
||||||
|
|
||||||
|
if (!loadedImages[imageToDisplay]) {
|
||||||
|
//image has not been loaded yet, we need to load the image first in memory to prevent flash of
|
||||||
|
//no content
|
||||||
|
|
||||||
|
var image = new Image();
|
||||||
|
image.onload = function () {
|
||||||
|
children[imageToDisplay].src = sources[imageToDisplay];
|
||||||
|
|
||||||
|
children[lastActiveImage].style.display = 'none';
|
||||||
|
children[imageToDisplay].style.display = 'block';
|
||||||
|
|
||||||
|
loadedImages[imageToDisplay] = true;
|
||||||
|
|
||||||
|
lastActiveImage = imageToDisplay;
|
||||||
|
};
|
||||||
|
|
||||||
|
image.src = sources[imageToDisplay];
|
||||||
|
} else {
|
||||||
|
children[lastActiveImage].style.display = 'none';
|
||||||
|
children[imageToDisplay].style.display = 'block';
|
||||||
|
lastActiveImage = imageToDisplay;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//make sure for initial check call the .src is set correctly
|
||||||
|
children[imageToDisplay].src = sources[imageToDisplay];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
element.resizeSensorInstance = new ResizeSensor(element, check);
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
function findResponsiveImages() {
|
||||||
|
var query = getQuery();
|
||||||
|
|
||||||
|
var elements = query('[data-responsive-image],[responsive-image]');
|
||||||
|
for (var i = 0, j = elements.length; i < j; i++) {
|
||||||
|
attachResponsiveImage(elements[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var regex = /,?[\s\t]*([^,\n]*?)((?:\[[\s\t]*?(?:min|max)-(?:width|height)[\s\t]*?[~$\^]?=[\s\t]*?"[^"]*?"[\s\t]*?])+)([^,\n\s\{]*)/mgi;
|
||||||
|
var attrRegex = /\[[\s\t]*?(min|max)-(width|height)[\s\t]*?[~$\^]?=[\s\t]*?"([^"]*?)"[\s\t]*?]/mgi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} css
|
||||||
|
*/
|
||||||
|
function extractQuery(css) {
|
||||||
|
var match, smatch, attrs, attrMatch;
|
||||||
|
|
||||||
|
css = css.replace(/'/g, '"');
|
||||||
|
while (null !== (match = regex.exec(css))) {
|
||||||
|
smatch = match[1] + match[3];
|
||||||
|
attrs = match[2];
|
||||||
|
|
||||||
|
while (null !== (attrMatch = attrRegex.exec(attrs))) {
|
||||||
|
queueQuery(smatch, attrMatch[1], attrMatch[2], attrMatch[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {CssRule[]|String} rules
|
||||||
|
*/
|
||||||
|
function readRules(rules) {
|
||||||
|
var selector = '';
|
||||||
|
|
||||||
|
if (!rules) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('string' === typeof rules) {
|
||||||
|
rules = rules.toLowerCase();
|
||||||
|
if (-1 !== rules.indexOf('min-width') || -1 !== rules.indexOf('max-width')) {
|
||||||
|
extractQuery(rules);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i = 0, j = rules.length; i < j; i++) {
|
||||||
|
if (1 === rules[i].type) {
|
||||||
|
selector = rules[i].selectorText || rules[i].cssText;
|
||||||
|
if (-1 !== selector.indexOf('min-height') || -1 !== selector.indexOf('max-height')) {
|
||||||
|
extractQuery(selector);
|
||||||
|
} else if (-1 !== selector.indexOf('min-width') || -1 !== selector.indexOf('max-width')) {
|
||||||
|
extractQuery(selector);
|
||||||
|
}
|
||||||
|
} else if (4 === rules[i].type) {
|
||||||
|
readRules(rules[i].cssRules || rules[i].rules);
|
||||||
|
} else if (3 === rules[i].type) {
|
||||||
|
if(rules[i].styleSheet.hasOwnProperty("cssRules")) {
|
||||||
|
readRules(rules[i].styleSheet.cssRules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultCssInjected = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches all css rules and setups the event listener to all elements with element query rules..
|
||||||
|
*/
|
||||||
|
this.init = function () {
|
||||||
|
var animationStart = 'animationstart';
|
||||||
|
if (typeof document.documentElement.style['webkitAnimationName'] !== 'undefined') {
|
||||||
|
animationStart = 'webkitAnimationStart';
|
||||||
|
} else if (typeof document.documentElement.style['MozAnimationName'] !== 'undefined') {
|
||||||
|
animationStart = 'mozanimationstart';
|
||||||
|
} else if (typeof document.documentElement.style['OAnimationName'] !== 'undefined') {
|
||||||
|
animationStart = 'oanimationstart';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.addEventListener(animationStart, function (e) {
|
||||||
|
var element = e.target;
|
||||||
|
var styles = element && window.getComputedStyle(element, null);
|
||||||
|
var animationName = styles && styles.getPropertyValue('animation-name');
|
||||||
|
var requiresSetup = animationName && (-1 !== animationName.indexOf('element-queries'));
|
||||||
|
|
||||||
|
if (requiresSetup) {
|
||||||
|
element.elementQueriesSensor = new ResizeSensor(element, function () {
|
||||||
|
if (element.elementQueriesSetupInformation) {
|
||||||
|
element.elementQueriesSetupInformation.call();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var sensorStyles = window.getComputedStyle(element.resizeSensor, null);
|
||||||
|
var id = sensorStyles.getPropertyValue('min-width');
|
||||||
|
id = parseInt(id.replace('px', ''));
|
||||||
|
setupElement(e.target, idToSelectorMapping[id]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!defaultCssInjected) {
|
||||||
|
cssStyleElement = document.createElement('style');
|
||||||
|
cssStyleElement.type = 'text/css';
|
||||||
|
cssStyleElement.innerHTML = '[responsive-image] > img, [data-responsive-image] {overflow: hidden; padding: 0; } [responsive-image] > img, [data-responsive-image] > img {width: 100%;}';
|
||||||
|
|
||||||
|
//safari wants at least one rule in keyframes to start working
|
||||||
|
cssStyleElement.innerHTML += '\n@keyframes element-queries { 0% { visibility: inherit; } }';
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(cssStyleElement);
|
||||||
|
defaultCssInjected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0, j = document.styleSheets.length; i < j; i++) {
|
||||||
|
try {
|
||||||
|
if (document.styleSheets[i].href && 0 === document.styleSheets[i].href.indexOf('file://')) {
|
||||||
|
console.warn("CssElementQueries: unable to parse local css files, " + document.styleSheets[i].href);
|
||||||
|
}
|
||||||
|
|
||||||
|
readRules(document.styleSheets[i].cssRules || document.styleSheets[i].rules || document.styleSheets[i].cssText);
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
findResponsiveImages();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go through all collected rules (readRules()) and attach the resize-listener.
|
||||||
|
* Not necessary to call it manually, since we detect automatically when new elements
|
||||||
|
* are available in the DOM. However, sometimes handy for dirty DOM modifications.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} container only elements of the container are considered (document.body if not set)
|
||||||
|
*/
|
||||||
|
this.findElementQueriesElements = function (container) {
|
||||||
|
findElementQueriesElements(container);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.update = function () {
|
||||||
|
this.init();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ElementQueries.update = function () {
|
||||||
|
ElementQueries.instance.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all sensor and elementquery information from the element.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
*/
|
||||||
|
ElementQueries.detach = function (element) {
|
||||||
|
if (element.elementQueriesSetupInformation) {
|
||||||
|
//element queries
|
||||||
|
element.elementQueriesSensor.detach();
|
||||||
|
delete element.elementQueriesSetupInformation;
|
||||||
|
delete element.elementQueriesSensor;
|
||||||
|
|
||||||
|
} else if (element.resizeSensorInstance) {
|
||||||
|
//responsive image
|
||||||
|
|
||||||
|
element.resizeSensorInstance.detach();
|
||||||
|
delete element.resizeSensorInstance;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ElementQueries.init = function () {
|
||||||
|
if (!ElementQueries.instance) {
|
||||||
|
ElementQueries.instance = new ElementQueries();
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementQueries.instance.init();
|
||||||
|
};
|
||||||
|
|
||||||
|
var domLoaded = function (callback) {
|
||||||
|
/* Mozilla, Chrome, Opera */
|
||||||
|
if (document.addEventListener) {
|
||||||
|
document.addEventListener('DOMContentLoaded', callback, false);
|
||||||
|
}
|
||||||
|
/* Safari, iCab, Konqueror */
|
||||||
|
else if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
|
||||||
|
var DOMLoadTimer = setInterval(function () {
|
||||||
|
if (/loaded|complete/i.test(document.readyState)) {
|
||||||
|
callback();
|
||||||
|
clearInterval(DOMLoadTimer);
|
||||||
|
}
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
/* Other web browsers */
|
||||||
|
else window.onload = callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
ElementQueries.findElementQueriesElements = function (container) {
|
||||||
|
ElementQueries.instance.findElementQueriesElements(container);
|
||||||
|
};
|
||||||
|
|
||||||
|
ElementQueries.listen = function () {
|
||||||
|
domLoaded(ElementQueries.init);
|
||||||
|
};
|
||||||
|
|
||||||
|
return ElementQueries;
|
||||||
|
|
||||||
|
}));
|
@ -0,0 +1,33 @@
|
|||||||
|
export declare type ResizeSensorCallback = (size: { width: number; height: number; }) => void;
|
||||||
|
|
||||||
|
export declare class ResizeSensor {
|
||||||
|
/**
|
||||||
|
* Creates a new resize sensor on given elements. The provided callback is called max 1 times per requestAnimationFrame and
|
||||||
|
* is called initially.
|
||||||
|
*/
|
||||||
|
constructor(element: Element | Element[], callback: ResizeSensorCallback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the resize sensor, and stops listening to resize events.
|
||||||
|
*/
|
||||||
|
detach(callback?: ResizeSensorCallback): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the resize sensors, so for the next element resize is correctly detected. This is rare cases necessary
|
||||||
|
* when the resize sensor isn't initialised correctly or is in a broken state due to DOM modifications.
|
||||||
|
*/
|
||||||
|
reset(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the resize sensor, and stops listening to resize events.
|
||||||
|
*/
|
||||||
|
static detach(element: Element | Element[], callback?: ResizeSensorCallback): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the resize sensors, so for the next element resize is correctly detected. This is rare cases necessary
|
||||||
|
* when the resize sensor isn't initialised correctly or is in a broken state due to DOM modifications.
|
||||||
|
*/
|
||||||
|
static reset(element: Element | Element[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ResizeSensor;
|
@ -0,0 +1,367 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright Marc J. Schmidt. See the LICENSE file at the top-level
|
||||||
|
* directory of this distribution and at
|
||||||
|
* https://github.com/marcj/css-element-queries/blob/master/LICENSE.
|
||||||
|
*/
|
||||||
|
(function (root, factory) {
|
||||||
|
if (typeof define === "function" && define.amd) {
|
||||||
|
define(factory);
|
||||||
|
} else if (typeof exports === "object") {
|
||||||
|
module.exports = factory();
|
||||||
|
} else {
|
||||||
|
root.ResizeSensor = factory();
|
||||||
|
}
|
||||||
|
}(typeof window !== 'undefined' ? window : this, function () {
|
||||||
|
|
||||||
|
// Make sure it does not throw in a SSR (Server Side Rendering) situation
|
||||||
|
if (typeof window === "undefined") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// https://github.com/Semantic-Org/Semantic-UI/issues/3855
|
||||||
|
// https://github.com/marcj/css-element-queries/issues/257
|
||||||
|
var globalWindow = typeof window != 'undefined' && window.Math == Math
|
||||||
|
? window
|
||||||
|
: typeof self != 'undefined' && self.Math == Math
|
||||||
|
? self
|
||||||
|
: Function('return this')();
|
||||||
|
// Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor.
|
||||||
|
// In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and
|
||||||
|
// would generate too many unnecessary events.
|
||||||
|
var requestAnimationFrame = globalWindow.requestAnimationFrame ||
|
||||||
|
globalWindow.mozRequestAnimationFrame ||
|
||||||
|
globalWindow.webkitRequestAnimationFrame ||
|
||||||
|
function (fn) {
|
||||||
|
return globalWindow.setTimeout(fn, 20);
|
||||||
|
};
|
||||||
|
|
||||||
|
var cancelAnimationFrame = globalWindow.cancelAnimationFrame ||
|
||||||
|
globalWindow.mozCancelAnimationFrame ||
|
||||||
|
globalWindow.webkitCancelAnimationFrame ||
|
||||||
|
function (timer) {
|
||||||
|
globalWindow.clearTimeout(timer);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over each of the provided element(s).
|
||||||
|
*
|
||||||
|
* @param {HTMLElement|HTMLElement[]} elements
|
||||||
|
* @param {Function} callback
|
||||||
|
*/
|
||||||
|
function forEachElement(elements, callback){
|
||||||
|
var elementsType = Object.prototype.toString.call(elements);
|
||||||
|
var isCollectionTyped = ('[object Array]' === elementsType
|
||||||
|
|| ('[object NodeList]' === elementsType)
|
||||||
|
|| ('[object HTMLCollection]' === elementsType)
|
||||||
|
|| ('[object Object]' === elementsType)
|
||||||
|
|| ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery
|
||||||
|
|| ('undefined' !== typeof Elements && elements instanceof Elements) //mootools
|
||||||
|
);
|
||||||
|
var i = 0, j = elements.length;
|
||||||
|
if (isCollectionTyped) {
|
||||||
|
for (; i < j; i++) {
|
||||||
|
callback(elements[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback(elements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get element size
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @returns {Object} {width, height}
|
||||||
|
*/
|
||||||
|
function getElementSize(element) {
|
||||||
|
if (!element.getBoundingClientRect) {
|
||||||
|
return {
|
||||||
|
width: element.offsetWidth,
|
||||||
|
height: element.offsetHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rect = element.getBoundingClientRect();
|
||||||
|
return {
|
||||||
|
width: Math.round(rect.width),
|
||||||
|
height: Math.round(rect.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply CSS styles to element.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @param {Object} style
|
||||||
|
*/
|
||||||
|
function setStyle(element, style) {
|
||||||
|
Object.keys(style).forEach(function(key) {
|
||||||
|
element.style[key] = style[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for dimension change detection.
|
||||||
|
*
|
||||||
|
* @param {Element|Element[]|Elements|jQuery} element
|
||||||
|
* @param {Function} callback
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
var ResizeSensor = function(element, callback) {
|
||||||
|
//Is used when checking in reset() only for invisible elements
|
||||||
|
var lastAnimationFrameForInvisibleCheck = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function EventQueue() {
|
||||||
|
var q = [];
|
||||||
|
this.add = function(ev) {
|
||||||
|
q.push(ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
var i, j;
|
||||||
|
this.call = function(sizeInfo) {
|
||||||
|
for (i = 0, j = q.length; i < j; i++) {
|
||||||
|
q[i].call(this, sizeInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.remove = function(ev) {
|
||||||
|
var newQueue = [];
|
||||||
|
for(i = 0, j = q.length; i < j; i++) {
|
||||||
|
if(q[i] !== ev) newQueue.push(q[i]);
|
||||||
|
}
|
||||||
|
q = newQueue;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.length = function() {
|
||||||
|
return q.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @param {Function} resized
|
||||||
|
*/
|
||||||
|
function attachResizeEvent(element, resized) {
|
||||||
|
if (!element) return;
|
||||||
|
if (element.resizedAttached) {
|
||||||
|
element.resizedAttached.add(resized);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.resizedAttached = new EventQueue();
|
||||||
|
element.resizedAttached.add(resized);
|
||||||
|
|
||||||
|
element.resizeSensor = document.createElement('div');
|
||||||
|
element.resizeSensor.dir = 'ltr';
|
||||||
|
element.resizeSensor.className = 'resize-sensor';
|
||||||
|
|
||||||
|
var style = {
|
||||||
|
pointerEvents: 'none',
|
||||||
|
position: 'absolute',
|
||||||
|
left: '0px',
|
||||||
|
top: '0px',
|
||||||
|
right: '0px',
|
||||||
|
bottom: '0px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
zIndex: '-1',
|
||||||
|
visibility: 'hidden',
|
||||||
|
maxWidth: '100%'
|
||||||
|
};
|
||||||
|
var styleChild = {
|
||||||
|
position: 'absolute',
|
||||||
|
left: '0px',
|
||||||
|
top: '0px',
|
||||||
|
transition: '0s',
|
||||||
|
};
|
||||||
|
|
||||||
|
setStyle(element.resizeSensor, style);
|
||||||
|
|
||||||
|
var expand = document.createElement('div');
|
||||||
|
expand.className = 'resize-sensor-expand';
|
||||||
|
setStyle(expand, style);
|
||||||
|
|
||||||
|
var expandChild = document.createElement('div');
|
||||||
|
setStyle(expandChild, styleChild);
|
||||||
|
expand.appendChild(expandChild);
|
||||||
|
|
||||||
|
var shrink = document.createElement('div');
|
||||||
|
shrink.className = 'resize-sensor-shrink';
|
||||||
|
setStyle(shrink, style);
|
||||||
|
|
||||||
|
var shrinkChild = document.createElement('div');
|
||||||
|
setStyle(shrinkChild, styleChild);
|
||||||
|
setStyle(shrinkChild, { width: '200%', height: '200%' });
|
||||||
|
shrink.appendChild(shrinkChild);
|
||||||
|
|
||||||
|
element.resizeSensor.appendChild(expand);
|
||||||
|
element.resizeSensor.appendChild(shrink);
|
||||||
|
element.appendChild(element.resizeSensor);
|
||||||
|
|
||||||
|
var computedStyle = window.getComputedStyle(element);
|
||||||
|
var position = computedStyle ? computedStyle.getPropertyValue('position') : null;
|
||||||
|
if ('absolute' !== position && 'relative' !== position && 'fixed' !== position && 'sticky' !== position) {
|
||||||
|
element.style.position = 'relative';
|
||||||
|
}
|
||||||
|
|
||||||
|
var dirty = false;
|
||||||
|
|
||||||
|
//last request animation frame id used in onscroll event
|
||||||
|
var rafId = 0;
|
||||||
|
var size = getElementSize(element);
|
||||||
|
var lastWidth = 0;
|
||||||
|
var lastHeight = 0;
|
||||||
|
var initialHiddenCheck = true;
|
||||||
|
lastAnimationFrameForInvisibleCheck = 0;
|
||||||
|
|
||||||
|
var resetExpandShrink = function () {
|
||||||
|
var width = element.offsetWidth;
|
||||||
|
var height = element.offsetHeight;
|
||||||
|
|
||||||
|
expandChild.style.width = (width + 10) + 'px';
|
||||||
|
expandChild.style.height = (height + 10) + 'px';
|
||||||
|
|
||||||
|
expand.scrollLeft = width + 10;
|
||||||
|
expand.scrollTop = height + 10;
|
||||||
|
|
||||||
|
shrink.scrollLeft = width + 10;
|
||||||
|
shrink.scrollTop = height + 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
var reset = function() {
|
||||||
|
// Check if element is hidden
|
||||||
|
if (initialHiddenCheck) {
|
||||||
|
var invisible = element.offsetWidth === 0 && element.offsetHeight === 0;
|
||||||
|
if (invisible) {
|
||||||
|
// Check in next frame
|
||||||
|
if (!lastAnimationFrameForInvisibleCheck){
|
||||||
|
lastAnimationFrameForInvisibleCheck = requestAnimationFrame(function(){
|
||||||
|
lastAnimationFrameForInvisibleCheck = 0;
|
||||||
|
reset();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Stop checking
|
||||||
|
initialHiddenCheck = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resetExpandShrink();
|
||||||
|
};
|
||||||
|
element.resizeSensor.resetSensor = reset;
|
||||||
|
|
||||||
|
var onResized = function() {
|
||||||
|
rafId = 0;
|
||||||
|
|
||||||
|
if (!dirty) return;
|
||||||
|
|
||||||
|
lastWidth = size.width;
|
||||||
|
lastHeight = size.height;
|
||||||
|
|
||||||
|
if (element.resizedAttached) {
|
||||||
|
element.resizedAttached.call(size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var onScroll = function() {
|
||||||
|
size = getElementSize(element);
|
||||||
|
dirty = size.width !== lastWidth || size.height !== lastHeight;
|
||||||
|
|
||||||
|
if (dirty && !rafId) {
|
||||||
|
rafId = requestAnimationFrame(onResized);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
var addEvent = function(el, name, cb) {
|
||||||
|
if (el.attachEvent) {
|
||||||
|
el.attachEvent('on' + name, cb);
|
||||||
|
} else {
|
||||||
|
el.addEventListener(name, cb);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
addEvent(expand, 'scroll', onScroll);
|
||||||
|
addEvent(shrink, 'scroll', onScroll);
|
||||||
|
|
||||||
|
// Fix for custom Elements and invisible elements
|
||||||
|
lastAnimationFrameForInvisibleCheck = requestAnimationFrame(function(){
|
||||||
|
lastAnimationFrameForInvisibleCheck = 0;
|
||||||
|
reset();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
forEachElement(element, function(elem){
|
||||||
|
attachResizeEvent(elem, callback);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.detach = function(ev) {
|
||||||
|
// clean up the unfinished animation frame to prevent a potential endless requestAnimationFrame of reset
|
||||||
|
if (!lastAnimationFrameForInvisibleCheck) {
|
||||||
|
cancelAnimationFrame(lastAnimationFrameForInvisibleCheck);
|
||||||
|
lastAnimationFrameForInvisibleCheck = 0;
|
||||||
|
}
|
||||||
|
ResizeSensor.detach(element, ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
element.resizeSensor.resetSensor();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ResizeSensor.reset = function(element) {
|
||||||
|
forEachElement(element, function(elem){
|
||||||
|
elem.resizeSensor.resetSensor();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ResizeSensor.detach = function(element, ev) {
|
||||||
|
forEachElement(element, function(elem){
|
||||||
|
if (!elem) return;
|
||||||
|
if(elem.resizedAttached && typeof ev === "function"){
|
||||||
|
elem.resizedAttached.remove(ev);
|
||||||
|
if(elem.resizedAttached.length()) return;
|
||||||
|
}
|
||||||
|
if (elem.resizeSensor) {
|
||||||
|
if (elem.contains(elem.resizeSensor)) {
|
||||||
|
elem.removeChild(elem.resizeSensor);
|
||||||
|
}
|
||||||
|
delete elem.resizeSensor;
|
||||||
|
delete elem.resizedAttached;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof MutationObserver !== "undefined") {
|
||||||
|
var observer = new MutationObserver(function (mutations) {
|
||||||
|
for (var i in mutations) {
|
||||||
|
if (mutations.hasOwnProperty(i)) {
|
||||||
|
var items = mutations[i].addedNodes;
|
||||||
|
for (var j = 0; j < items.length; j++) {
|
||||||
|
if (items[j].resizeSensor) {
|
||||||
|
ResizeSensor.reset(items[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function (event) {
|
||||||
|
observer.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResizeSensor;
|
||||||
|
|
||||||
|
}));
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"lib" : ["dom","es6","dom.iterable","scripthost", "es2015.iterable", "es2015.collection"]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
parserOptions:
|
||||||
|
sourceType: module
|
||||||
|
|
||||||
|
env:
|
||||||
|
es6: true
|
||||||
|
browser: true
|
||||||
|
|
||||||
|
extends:
|
||||||
|
"eslint:recommended"
|
||||||
|
|
||||||
|
rules:
|
||||||
|
no-cond-assign: 0
|
@ -0,0 +1,3 @@
|
|||||||
|
*.sublime-*
|
||||||
|
build/*.zip
|
||||||
|
test/
|
@ -0,0 +1,27 @@
|
|||||||
|
Copyright 2010-2016 Mike Bostock
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the author nor the names of contributors may be used to
|
||||||
|
endorse or promote products derived from this software without specific prior
|
||||||
|
written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -0,0 +1,590 @@
|
|||||||
|
// https://d3js.org/d3-array/ Version 1.2.1. Copyright 2017 Mike Bostock.
|
||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||||
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
||||||
|
(factory((global.d3 = global.d3 || {})));
|
||||||
|
}(this, (function (exports) { 'use strict';
|
||||||
|
|
||||||
|
var ascending = function(a, b) {
|
||||||
|
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
|
||||||
|
};
|
||||||
|
|
||||||
|
var bisector = function(compare) {
|
||||||
|
if (compare.length === 1) compare = ascendingComparator(compare);
|
||||||
|
return {
|
||||||
|
left: function(a, x, lo, hi) {
|
||||||
|
if (lo == null) lo = 0;
|
||||||
|
if (hi == null) hi = a.length;
|
||||||
|
while (lo < hi) {
|
||||||
|
var mid = lo + hi >>> 1;
|
||||||
|
if (compare(a[mid], x) < 0) lo = mid + 1;
|
||||||
|
else hi = mid;
|
||||||
|
}
|
||||||
|
return lo;
|
||||||
|
},
|
||||||
|
right: function(a, x, lo, hi) {
|
||||||
|
if (lo == null) lo = 0;
|
||||||
|
if (hi == null) hi = a.length;
|
||||||
|
while (lo < hi) {
|
||||||
|
var mid = lo + hi >>> 1;
|
||||||
|
if (compare(a[mid], x) > 0) hi = mid;
|
||||||
|
else lo = mid + 1;
|
||||||
|
}
|
||||||
|
return lo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function ascendingComparator(f) {
|
||||||
|
return function(d, x) {
|
||||||
|
return ascending(f(d), x);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var ascendingBisect = bisector(ascending);
|
||||||
|
var bisectRight = ascendingBisect.right;
|
||||||
|
var bisectLeft = ascendingBisect.left;
|
||||||
|
|
||||||
|
var pairs = function(array, f) {
|
||||||
|
if (f == null) f = pair;
|
||||||
|
var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
|
||||||
|
while (i < n) pairs[i] = f(p, p = array[++i]);
|
||||||
|
return pairs;
|
||||||
|
};
|
||||||
|
|
||||||
|
function pair(a, b) {
|
||||||
|
return [a, b];
|
||||||
|
}
|
||||||
|
|
||||||
|
var cross = function(values0, values1, reduce) {
|
||||||
|
var n0 = values0.length,
|
||||||
|
n1 = values1.length,
|
||||||
|
values = new Array(n0 * n1),
|
||||||
|
i0,
|
||||||
|
i1,
|
||||||
|
i,
|
||||||
|
value0;
|
||||||
|
|
||||||
|
if (reduce == null) reduce = pair;
|
||||||
|
|
||||||
|
for (i0 = i = 0; i0 < n0; ++i0) {
|
||||||
|
for (value0 = values0[i0], i1 = 0; i1 < n1; ++i1, ++i) {
|
||||||
|
values[i] = reduce(value0, values1[i1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
|
||||||
|
var descending = function(a, b) {
|
||||||
|
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
|
||||||
|
};
|
||||||
|
|
||||||
|
var number = function(x) {
|
||||||
|
return x === null ? NaN : +x;
|
||||||
|
};
|
||||||
|
|
||||||
|
var variance = function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
m = 0,
|
||||||
|
i = -1,
|
||||||
|
mean = 0,
|
||||||
|
value,
|
||||||
|
delta,
|
||||||
|
sum = 0;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) {
|
||||||
|
if (!isNaN(value = number(values[i]))) {
|
||||||
|
delta = value - mean;
|
||||||
|
mean += delta / ++m;
|
||||||
|
sum += delta * (value - mean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) {
|
||||||
|
if (!isNaN(value = number(valueof(values[i], i, values)))) {
|
||||||
|
delta = value - mean;
|
||||||
|
mean += delta / ++m;
|
||||||
|
sum += delta * (value - mean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m > 1) return sum / (m - 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
var deviation = function(array, f) {
|
||||||
|
var v = variance(array, f);
|
||||||
|
return v ? Math.sqrt(v) : v;
|
||||||
|
};
|
||||||
|
|
||||||
|
var extent = function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
min,
|
||||||
|
max;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = values[i]) != null && value >= value) {
|
||||||
|
min = max = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = values[i]) != null) {
|
||||||
|
if (min > value) min = value;
|
||||||
|
if (max < value) max = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null && value >= value) {
|
||||||
|
min = max = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null) {
|
||||||
|
if (min > value) min = value;
|
||||||
|
if (max < value) max = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [min, max];
|
||||||
|
};
|
||||||
|
|
||||||
|
var array = Array.prototype;
|
||||||
|
|
||||||
|
var slice = array.slice;
|
||||||
|
var map = array.map;
|
||||||
|
|
||||||
|
var constant = function(x) {
|
||||||
|
return function() {
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var identity = function(x) {
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
|
||||||
|
var range = function(start, stop, step) {
|
||||||
|
start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
|
||||||
|
|
||||||
|
var i = -1,
|
||||||
|
n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
|
||||||
|
range = new Array(n);
|
||||||
|
|
||||||
|
while (++i < n) {
|
||||||
|
range[i] = start + i * step;
|
||||||
|
}
|
||||||
|
|
||||||
|
return range;
|
||||||
|
};
|
||||||
|
|
||||||
|
var e10 = Math.sqrt(50);
|
||||||
|
var e5 = Math.sqrt(10);
|
||||||
|
var e2 = Math.sqrt(2);
|
||||||
|
|
||||||
|
var ticks = function(start, stop, count) {
|
||||||
|
var reverse,
|
||||||
|
i = -1,
|
||||||
|
n,
|
||||||
|
ticks,
|
||||||
|
step;
|
||||||
|
|
||||||
|
stop = +stop, start = +start, count = +count;
|
||||||
|
if (start === stop && count > 0) return [start];
|
||||||
|
if (reverse = stop < start) n = start, start = stop, stop = n;
|
||||||
|
if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
|
||||||
|
|
||||||
|
if (step > 0) {
|
||||||
|
start = Math.ceil(start / step);
|
||||||
|
stop = Math.floor(stop / step);
|
||||||
|
ticks = new Array(n = Math.ceil(stop - start + 1));
|
||||||
|
while (++i < n) ticks[i] = (start + i) * step;
|
||||||
|
} else {
|
||||||
|
start = Math.floor(start * step);
|
||||||
|
stop = Math.ceil(stop * step);
|
||||||
|
ticks = new Array(n = Math.ceil(start - stop + 1));
|
||||||
|
while (++i < n) ticks[i] = (start - i) / step;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverse) ticks.reverse();
|
||||||
|
|
||||||
|
return ticks;
|
||||||
|
};
|
||||||
|
|
||||||
|
function tickIncrement(start, stop, count) {
|
||||||
|
var step = (stop - start) / Math.max(0, count),
|
||||||
|
power = Math.floor(Math.log(step) / Math.LN10),
|
||||||
|
error = step / Math.pow(10, power);
|
||||||
|
return power >= 0
|
||||||
|
? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)
|
||||||
|
: -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tickStep(start, stop, count) {
|
||||||
|
var step0 = Math.abs(stop - start) / Math.max(0, count),
|
||||||
|
step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
|
||||||
|
error = step0 / step1;
|
||||||
|
if (error >= e10) step1 *= 10;
|
||||||
|
else if (error >= e5) step1 *= 5;
|
||||||
|
else if (error >= e2) step1 *= 2;
|
||||||
|
return stop < start ? -step1 : step1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sturges = function(values) {
|
||||||
|
return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
var histogram = function() {
|
||||||
|
var value = identity,
|
||||||
|
domain = extent,
|
||||||
|
threshold = sturges;
|
||||||
|
|
||||||
|
function histogram(data) {
|
||||||
|
var i,
|
||||||
|
n = data.length,
|
||||||
|
x,
|
||||||
|
values = new Array(n);
|
||||||
|
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
values[i] = value(data[i], i, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
var xz = domain(values),
|
||||||
|
x0 = xz[0],
|
||||||
|
x1 = xz[1],
|
||||||
|
tz = threshold(values, x0, x1);
|
||||||
|
|
||||||
|
// Convert number of thresholds into uniform thresholds.
|
||||||
|
if (!Array.isArray(tz)) {
|
||||||
|
tz = tickStep(x0, x1, tz);
|
||||||
|
tz = range(Math.ceil(x0 / tz) * tz, Math.floor(x1 / tz) * tz, tz); // exclusive
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any thresholds outside the domain.
|
||||||
|
var m = tz.length;
|
||||||
|
while (tz[0] <= x0) tz.shift(), --m;
|
||||||
|
while (tz[m - 1] > x1) tz.pop(), --m;
|
||||||
|
|
||||||
|
var bins = new Array(m + 1),
|
||||||
|
bin;
|
||||||
|
|
||||||
|
// Initialize bins.
|
||||||
|
for (i = 0; i <= m; ++i) {
|
||||||
|
bin = bins[i] = [];
|
||||||
|
bin.x0 = i > 0 ? tz[i - 1] : x0;
|
||||||
|
bin.x1 = i < m ? tz[i] : x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign data to bins by value, ignoring any outside the domain.
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
x = values[i];
|
||||||
|
if (x0 <= x && x <= x1) {
|
||||||
|
bins[bisectRight(tz, x, 0, m)].push(data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bins;
|
||||||
|
}
|
||||||
|
|
||||||
|
histogram.value = function(_) {
|
||||||
|
return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
|
||||||
|
};
|
||||||
|
|
||||||
|
histogram.domain = function(_) {
|
||||||
|
return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
|
||||||
|
};
|
||||||
|
|
||||||
|
histogram.thresholds = function(_) {
|
||||||
|
return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold;
|
||||||
|
};
|
||||||
|
|
||||||
|
return histogram;
|
||||||
|
};
|
||||||
|
|
||||||
|
var quantile = function(values, p, valueof) {
|
||||||
|
if (valueof == null) valueof = number;
|
||||||
|
if (!(n = values.length)) return;
|
||||||
|
if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
|
||||||
|
if (p >= 1) return +valueof(values[n - 1], n - 1, values);
|
||||||
|
var n,
|
||||||
|
i = (n - 1) * p,
|
||||||
|
i0 = Math.floor(i),
|
||||||
|
value0 = +valueof(values[i0], i0, values),
|
||||||
|
value1 = +valueof(values[i0 + 1], i0 + 1, values);
|
||||||
|
return value0 + (value1 - value0) * (i - i0);
|
||||||
|
};
|
||||||
|
|
||||||
|
var freedmanDiaconis = function(values, min, max) {
|
||||||
|
values = map.call(values, number).sort(ascending);
|
||||||
|
return Math.ceil((max - min) / (2 * (quantile(values, 0.75) - quantile(values, 0.25)) * Math.pow(values.length, -1 / 3)));
|
||||||
|
};
|
||||||
|
|
||||||
|
var scott = function(values, min, max) {
|
||||||
|
return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
|
||||||
|
};
|
||||||
|
|
||||||
|
var max = function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
max;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = values[i]) != null && value >= value) {
|
||||||
|
max = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = values[i]) != null && value > max) {
|
||||||
|
max = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null && value >= value) {
|
||||||
|
max = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null && value > max) {
|
||||||
|
max = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max;
|
||||||
|
};
|
||||||
|
|
||||||
|
var mean = function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
m = n,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
sum = 0;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) {
|
||||||
|
if (!isNaN(value = number(values[i]))) sum += value;
|
||||||
|
else --m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) {
|
||||||
|
if (!isNaN(value = number(valueof(values[i], i, values)))) sum += value;
|
||||||
|
else --m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m) return sum / m;
|
||||||
|
};
|
||||||
|
|
||||||
|
var median = function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
numbers = [];
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) {
|
||||||
|
if (!isNaN(value = number(values[i]))) {
|
||||||
|
numbers.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) {
|
||||||
|
if (!isNaN(value = number(valueof(values[i], i, values)))) {
|
||||||
|
numbers.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return quantile(numbers.sort(ascending), 0.5);
|
||||||
|
};
|
||||||
|
|
||||||
|
var merge = function(arrays) {
|
||||||
|
var n = arrays.length,
|
||||||
|
m,
|
||||||
|
i = -1,
|
||||||
|
j = 0,
|
||||||
|
merged,
|
||||||
|
array;
|
||||||
|
|
||||||
|
while (++i < n) j += arrays[i].length;
|
||||||
|
merged = new Array(j);
|
||||||
|
|
||||||
|
while (--n >= 0) {
|
||||||
|
array = arrays[n];
|
||||||
|
m = array.length;
|
||||||
|
while (--m >= 0) {
|
||||||
|
merged[--j] = array[m];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged;
|
||||||
|
};
|
||||||
|
|
||||||
|
var min = function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
min;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = values[i]) != null && value >= value) {
|
||||||
|
min = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = values[i]) != null && min > value) {
|
||||||
|
min = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null && value >= value) {
|
||||||
|
min = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null && min > value) {
|
||||||
|
min = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return min;
|
||||||
|
};
|
||||||
|
|
||||||
|
var permute = function(array, indexes) {
|
||||||
|
var i = indexes.length, permutes = new Array(i);
|
||||||
|
while (i--) permutes[i] = array[indexes[i]];
|
||||||
|
return permutes;
|
||||||
|
};
|
||||||
|
|
||||||
|
var scan = function(values, compare) {
|
||||||
|
if (!(n = values.length)) return;
|
||||||
|
var n,
|
||||||
|
i = 0,
|
||||||
|
j = 0,
|
||||||
|
xi,
|
||||||
|
xj = values[j];
|
||||||
|
|
||||||
|
if (compare == null) compare = ascending;
|
||||||
|
|
||||||
|
while (++i < n) {
|
||||||
|
if (compare(xi = values[i], xj) < 0 || compare(xj, xj) !== 0) {
|
||||||
|
xj = xi, j = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compare(xj, xj) === 0) return j;
|
||||||
|
};
|
||||||
|
|
||||||
|
var shuffle = function(array, i0, i1) {
|
||||||
|
var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
|
||||||
|
t,
|
||||||
|
i;
|
||||||
|
|
||||||
|
while (m) {
|
||||||
|
i = Math.random() * m-- | 0;
|
||||||
|
t = array[m + i0];
|
||||||
|
array[m + i0] = array[i + i0];
|
||||||
|
array[i + i0] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
};
|
||||||
|
|
||||||
|
var sum = function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
sum = 0;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) {
|
||||||
|
if (value = +values[i]) sum += value; // Note: zero and null are equivalent.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) {
|
||||||
|
if (value = +valueof(values[i], i, values)) sum += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
};
|
||||||
|
|
||||||
|
var transpose = function(matrix) {
|
||||||
|
if (!(n = matrix.length)) return [];
|
||||||
|
for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
|
||||||
|
for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
|
||||||
|
row[j] = matrix[j][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transpose;
|
||||||
|
};
|
||||||
|
|
||||||
|
function length(d) {
|
||||||
|
return d.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
var zip = function() {
|
||||||
|
return transpose(arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.bisect = bisectRight;
|
||||||
|
exports.bisectRight = bisectRight;
|
||||||
|
exports.bisectLeft = bisectLeft;
|
||||||
|
exports.ascending = ascending;
|
||||||
|
exports.bisector = bisector;
|
||||||
|
exports.cross = cross;
|
||||||
|
exports.descending = descending;
|
||||||
|
exports.deviation = deviation;
|
||||||
|
exports.extent = extent;
|
||||||
|
exports.histogram = histogram;
|
||||||
|
exports.thresholdFreedmanDiaconis = freedmanDiaconis;
|
||||||
|
exports.thresholdScott = scott;
|
||||||
|
exports.thresholdSturges = sturges;
|
||||||
|
exports.max = max;
|
||||||
|
exports.mean = mean;
|
||||||
|
exports.median = median;
|
||||||
|
exports.merge = merge;
|
||||||
|
exports.min = min;
|
||||||
|
exports.pairs = pairs;
|
||||||
|
exports.permute = permute;
|
||||||
|
exports.quantile = quantile;
|
||||||
|
exports.range = range;
|
||||||
|
exports.scan = scan;
|
||||||
|
exports.shuffle = shuffle;
|
||||||
|
exports.sum = sum;
|
||||||
|
exports.ticks = ticks;
|
||||||
|
exports.tickIncrement = tickIncrement;
|
||||||
|
exports.tickStep = tickStep;
|
||||||
|
exports.transpose = transpose;
|
||||||
|
exports.variance = variance;
|
||||||
|
exports.zip = zip;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
})));
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 9.9 KiB |
@ -0,0 +1,27 @@
|
|||||||
|
export {default as bisect, bisectRight, bisectLeft} from "./src/bisect";
|
||||||
|
export {default as ascending} from "./src/ascending";
|
||||||
|
export {default as bisector} from "./src/bisector";
|
||||||
|
export {default as cross} from "./src/cross";
|
||||||
|
export {default as descending} from "./src/descending";
|
||||||
|
export {default as deviation} from "./src/deviation";
|
||||||
|
export {default as extent} from "./src/extent";
|
||||||
|
export {default as histogram} from "./src/histogram";
|
||||||
|
export {default as thresholdFreedmanDiaconis} from "./src/threshold/freedmanDiaconis";
|
||||||
|
export {default as thresholdScott} from "./src/threshold/scott";
|
||||||
|
export {default as thresholdSturges} from "./src/threshold/sturges";
|
||||||
|
export {default as max} from "./src/max";
|
||||||
|
export {default as mean} from "./src/mean";
|
||||||
|
export {default as median} from "./src/median";
|
||||||
|
export {default as merge} from "./src/merge";
|
||||||
|
export {default as min} from "./src/min";
|
||||||
|
export {default as pairs} from "./src/pairs";
|
||||||
|
export {default as permute} from "./src/permute";
|
||||||
|
export {default as quantile} from "./src/quantile";
|
||||||
|
export {default as range} from "./src/range";
|
||||||
|
export {default as scan} from "./src/scan";
|
||||||
|
export {default as shuffle} from "./src/shuffle";
|
||||||
|
export {default as sum} from "./src/sum";
|
||||||
|
export {default as ticks, tickIncrement, tickStep} from "./src/ticks";
|
||||||
|
export {default as transpose} from "./src/transpose";
|
||||||
|
export {default as variance} from "./src/variance";
|
||||||
|
export {default as zip} from "./src/zip";
|
@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"_from": "d3-array@1.2.1",
|
||||||
|
"_id": "d3-array@1.2.1",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==",
|
||||||
|
"_location": "/d3-array",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "version",
|
||||||
|
"registry": true,
|
||||||
|
"raw": "d3-array@1.2.1",
|
||||||
|
"name": "d3-array",
|
||||||
|
"escapedName": "d3-array",
|
||||||
|
"rawSpec": "1.2.1",
|
||||||
|
"saveSpec": null,
|
||||||
|
"fetchSpec": "1.2.1"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"/d3",
|
||||||
|
"/d3-chord",
|
||||||
|
"/d3-geo",
|
||||||
|
"/d3-scale"
|
||||||
|
],
|
||||||
|
"_resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.1.tgz",
|
||||||
|
"_shasum": "d1ca33de2f6ac31efadb8e050a021d7e2396d5dc",
|
||||||
|
"_spec": "d3-array@1.2.1",
|
||||||
|
"_where": "C:\\Users\\a5640\\OneDrive - National ChengChi University\\programming\\Python\\flask\\sententree\\static\\node_modules\\d3",
|
||||||
|
"author": {
|
||||||
|
"name": "Mike Bostock",
|
||||||
|
"url": "http://bost.ocks.org/mike"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/d3/d3-array/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "Array manipulation, ordering, searching, summarizing, etc.",
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "3",
|
||||||
|
"package-preamble": "0.0",
|
||||||
|
"rollup": "0.41",
|
||||||
|
"seedrandom": "2",
|
||||||
|
"tape": "4",
|
||||||
|
"uglify-js": "^2.8.11"
|
||||||
|
},
|
||||||
|
"homepage": "https://d3js.org/d3-array/",
|
||||||
|
"jsnext:main": "index",
|
||||||
|
"keywords": [
|
||||||
|
"d3",
|
||||||
|
"d3-module",
|
||||||
|
"histogram",
|
||||||
|
"bisect",
|
||||||
|
"shuffle",
|
||||||
|
"statistics",
|
||||||
|
"search",
|
||||||
|
"sort",
|
||||||
|
"array"
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"main": "build/d3-array.js",
|
||||||
|
"module": "index",
|
||||||
|
"name": "d3-array",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/d3/d3-array.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"postpublish": "git push && git push --tags && cd ../d3.github.com && git pull && cp ../d3-array/build/d3-array.js d3-array.v1.js && cp ../d3-array/build/d3-array.min.js d3-array.v1.min.js && git add d3-array.v1.js d3-array.v1.min.js && git commit -m \"d3-array ${npm_package_version}\" && git push && cd - && zip -j build/d3-array.zip -- LICENSE README.md build/d3-array.js build/d3-array.min.js",
|
||||||
|
"prepublish": "npm run test && uglifyjs --preamble \"$(preamble)\" build/d3-array.js -c -m -o build/d3-array.min.js",
|
||||||
|
"pretest": "rm -rf build && mkdir build && rollup --banner \"$(preamble)\" -f umd -n d3 -o build/d3-array.js -- index.js",
|
||||||
|
"test": "tape 'test/**/*-test.js' && eslint index.js src"
|
||||||
|
},
|
||||||
|
"version": "1.2.1"
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
var array = Array.prototype;
|
||||||
|
|
||||||
|
export var slice = array.slice;
|
||||||
|
export var map = array.map;
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function(a, b) {
|
||||||
|
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import ascending from "./ascending";
|
||||||
|
import bisector from "./bisector";
|
||||||
|
|
||||||
|
var ascendingBisect = bisector(ascending);
|
||||||
|
export var bisectRight = ascendingBisect.right;
|
||||||
|
export var bisectLeft = ascendingBisect.left;
|
||||||
|
export default bisectRight;
|
@ -0,0 +1,33 @@
|
|||||||
|
import ascending from "./ascending";
|
||||||
|
|
||||||
|
export default function(compare) {
|
||||||
|
if (compare.length === 1) compare = ascendingComparator(compare);
|
||||||
|
return {
|
||||||
|
left: function(a, x, lo, hi) {
|
||||||
|
if (lo == null) lo = 0;
|
||||||
|
if (hi == null) hi = a.length;
|
||||||
|
while (lo < hi) {
|
||||||
|
var mid = lo + hi >>> 1;
|
||||||
|
if (compare(a[mid], x) < 0) lo = mid + 1;
|
||||||
|
else hi = mid;
|
||||||
|
}
|
||||||
|
return lo;
|
||||||
|
},
|
||||||
|
right: function(a, x, lo, hi) {
|
||||||
|
if (lo == null) lo = 0;
|
||||||
|
if (hi == null) hi = a.length;
|
||||||
|
while (lo < hi) {
|
||||||
|
var mid = lo + hi >>> 1;
|
||||||
|
if (compare(a[mid], x) > 0) hi = mid;
|
||||||
|
else lo = mid + 1;
|
||||||
|
}
|
||||||
|
return lo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function ascendingComparator(f) {
|
||||||
|
return function(d, x) {
|
||||||
|
return ascending(f(d), x);
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
export default function(x) {
|
||||||
|
return function() {
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import {pair} from "./pairs";
|
||||||
|
|
||||||
|
export default function(values0, values1, reduce) {
|
||||||
|
var n0 = values0.length,
|
||||||
|
n1 = values1.length,
|
||||||
|
values = new Array(n0 * n1),
|
||||||
|
i0,
|
||||||
|
i1,
|
||||||
|
i,
|
||||||
|
value0;
|
||||||
|
|
||||||
|
if (reduce == null) reduce = pair;
|
||||||
|
|
||||||
|
for (i0 = i = 0; i0 < n0; ++i0) {
|
||||||
|
for (value0 = values0[i0], i1 = 0; i1 < n1; ++i1, ++i) {
|
||||||
|
values[i] = reduce(value0, values1[i1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function(a, b) {
|
||||||
|
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
import variance from "./variance";
|
||||||
|
|
||||||
|
export default function(array, f) {
|
||||||
|
var v = variance(array, f);
|
||||||
|
return v ? Math.sqrt(v) : v;
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
export default function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
min,
|
||||||
|
max;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = values[i]) != null && value >= value) {
|
||||||
|
min = max = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = values[i]) != null) {
|
||||||
|
if (min > value) min = value;
|
||||||
|
if (max < value) max = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null && value >= value) {
|
||||||
|
min = max = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null) {
|
||||||
|
if (min > value) min = value;
|
||||||
|
if (max < value) max = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [min, max];
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
import {slice} from "./array";
|
||||||
|
import bisect from "./bisect";
|
||||||
|
import constant from "./constant";
|
||||||
|
import extent from "./extent";
|
||||||
|
import identity from "./identity";
|
||||||
|
import range from "./range";
|
||||||
|
import {tickStep} from "./ticks";
|
||||||
|
import sturges from "./threshold/sturges";
|
||||||
|
|
||||||
|
export default function() {
|
||||||
|
var value = identity,
|
||||||
|
domain = extent,
|
||||||
|
threshold = sturges;
|
||||||
|
|
||||||
|
function histogram(data) {
|
||||||
|
var i,
|
||||||
|
n = data.length,
|
||||||
|
x,
|
||||||
|
values = new Array(n);
|
||||||
|
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
values[i] = value(data[i], i, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
var xz = domain(values),
|
||||||
|
x0 = xz[0],
|
||||||
|
x1 = xz[1],
|
||||||
|
tz = threshold(values, x0, x1);
|
||||||
|
|
||||||
|
// Convert number of thresholds into uniform thresholds.
|
||||||
|
if (!Array.isArray(tz)) {
|
||||||
|
tz = tickStep(x0, x1, tz);
|
||||||
|
tz = range(Math.ceil(x0 / tz) * tz, Math.floor(x1 / tz) * tz, tz); // exclusive
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any thresholds outside the domain.
|
||||||
|
var m = tz.length;
|
||||||
|
while (tz[0] <= x0) tz.shift(), --m;
|
||||||
|
while (tz[m - 1] > x1) tz.pop(), --m;
|
||||||
|
|
||||||
|
var bins = new Array(m + 1),
|
||||||
|
bin;
|
||||||
|
|
||||||
|
// Initialize bins.
|
||||||
|
for (i = 0; i <= m; ++i) {
|
||||||
|
bin = bins[i] = [];
|
||||||
|
bin.x0 = i > 0 ? tz[i - 1] : x0;
|
||||||
|
bin.x1 = i < m ? tz[i] : x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign data to bins by value, ignoring any outside the domain.
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
x = values[i];
|
||||||
|
if (x0 <= x && x <= x1) {
|
||||||
|
bins[bisect(tz, x, 0, m)].push(data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bins;
|
||||||
|
}
|
||||||
|
|
||||||
|
histogram.value = function(_) {
|
||||||
|
return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
|
||||||
|
};
|
||||||
|
|
||||||
|
histogram.domain = function(_) {
|
||||||
|
return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
|
||||||
|
};
|
||||||
|
|
||||||
|
histogram.thresholds = function(_) {
|
||||||
|
return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold;
|
||||||
|
};
|
||||||
|
|
||||||
|
return histogram;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function(x) {
|
||||||
|
return x;
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
export default function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
max;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = values[i]) != null && value >= value) {
|
||||||
|
max = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = values[i]) != null && value > max) {
|
||||||
|
max = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null && value >= value) {
|
||||||
|
max = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null && value > max) {
|
||||||
|
max = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max;
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
import number from "./number";
|
||||||
|
|
||||||
|
export default function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
m = n,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
sum = 0;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) {
|
||||||
|
if (!isNaN(value = number(values[i]))) sum += value;
|
||||||
|
else --m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) {
|
||||||
|
if (!isNaN(value = number(valueof(values[i], i, values)))) sum += value;
|
||||||
|
else --m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m) return sum / m;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
import ascending from "./ascending";
|
||||||
|
import number from "./number";
|
||||||
|
import quantile from "./quantile";
|
||||||
|
|
||||||
|
export default function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
numbers = [];
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) {
|
||||||
|
if (!isNaN(value = number(values[i]))) {
|
||||||
|
numbers.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) {
|
||||||
|
if (!isNaN(value = number(valueof(values[i], i, values)))) {
|
||||||
|
numbers.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return quantile(numbers.sort(ascending), 0.5);
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
export default function(arrays) {
|
||||||
|
var n = arrays.length,
|
||||||
|
m,
|
||||||
|
i = -1,
|
||||||
|
j = 0,
|
||||||
|
merged,
|
||||||
|
array;
|
||||||
|
|
||||||
|
while (++i < n) j += arrays[i].length;
|
||||||
|
merged = new Array(j);
|
||||||
|
|
||||||
|
while (--n >= 0) {
|
||||||
|
array = arrays[n];
|
||||||
|
m = array.length;
|
||||||
|
while (--m >= 0) {
|
||||||
|
merged[--j] = array[m];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged;
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
export default function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
min;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = values[i]) != null && value >= value) {
|
||||||
|
min = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = values[i]) != null && min > value) {
|
||||||
|
min = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) { // Find the first comparable value.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null && value >= value) {
|
||||||
|
min = value;
|
||||||
|
while (++i < n) { // Compare the remaining values.
|
||||||
|
if ((value = valueof(values[i], i, values)) != null && min > value) {
|
||||||
|
min = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return min;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function(x) {
|
||||||
|
return x === null ? NaN : +x;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
export default function(array, f) {
|
||||||
|
if (f == null) f = pair;
|
||||||
|
var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
|
||||||
|
while (i < n) pairs[i] = f(p, p = array[++i]);
|
||||||
|
return pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pair(a, b) {
|
||||||
|
return [a, b];
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
export default function(array, indexes) {
|
||||||
|
var i = indexes.length, permutes = new Array(i);
|
||||||
|
while (i--) permutes[i] = array[indexes[i]];
|
||||||
|
return permutes;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
import number from "./number";
|
||||||
|
|
||||||
|
export default function(values, p, valueof) {
|
||||||
|
if (valueof == null) valueof = number;
|
||||||
|
if (!(n = values.length)) return;
|
||||||
|
if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
|
||||||
|
if (p >= 1) return +valueof(values[n - 1], n - 1, values);
|
||||||
|
var n,
|
||||||
|
i = (n - 1) * p,
|
||||||
|
i0 = Math.floor(i),
|
||||||
|
value0 = +valueof(values[i0], i0, values),
|
||||||
|
value1 = +valueof(values[i0 + 1], i0 + 1, values);
|
||||||
|
return value0 + (value1 - value0) * (i - i0);
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
export default function(start, stop, step) {
|
||||||
|
start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
|
||||||
|
|
||||||
|
var i = -1,
|
||||||
|
n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
|
||||||
|
range = new Array(n);
|
||||||
|
|
||||||
|
while (++i < n) {
|
||||||
|
range[i] = start + i * step;
|
||||||
|
}
|
||||||
|
|
||||||
|
return range;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
import ascending from "./ascending";
|
||||||
|
|
||||||
|
export default function(values, compare) {
|
||||||
|
if (!(n = values.length)) return;
|
||||||
|
var n,
|
||||||
|
i = 0,
|
||||||
|
j = 0,
|
||||||
|
xi,
|
||||||
|
xj = values[j];
|
||||||
|
|
||||||
|
if (compare == null) compare = ascending;
|
||||||
|
|
||||||
|
while (++i < n) {
|
||||||
|
if (compare(xi = values[i], xj) < 0 || compare(xj, xj) !== 0) {
|
||||||
|
xj = xi, j = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compare(xj, xj) === 0) return j;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
export default function(array, i0, i1) {
|
||||||
|
var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
|
||||||
|
t,
|
||||||
|
i;
|
||||||
|
|
||||||
|
while (m) {
|
||||||
|
i = Math.random() * m-- | 0;
|
||||||
|
t = array[m + i0];
|
||||||
|
array[m + i0] = array[i + i0];
|
||||||
|
array[i + i0] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
export default function(values, valueof) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1,
|
||||||
|
value,
|
||||||
|
sum = 0;
|
||||||
|
|
||||||
|
if (valueof == null) {
|
||||||
|
while (++i < n) {
|
||||||
|
if (value = +values[i]) sum += value; // Note: zero and null are equivalent.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (++i < n) {
|
||||||
|
if (value = +valueof(values[i], i, values)) sum += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
import {map} from "../array";
|
||||||
|
import ascending from "../ascending";
|
||||||
|
import number from "../number";
|
||||||
|
import quantile from "../quantile";
|
||||||
|
|
||||||
|
export default function(values, min, max) {
|
||||||
|
values = map.call(values, number).sort(ascending);
|
||||||
|
return Math.ceil((max - min) / (2 * (quantile(values, 0.75) - quantile(values, 0.25)) * Math.pow(values.length, -1 / 3)));
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
import deviation from "../deviation";
|
||||||
|
|
||||||
|
export default function(values, min, max) {
|
||||||
|
return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function(values) {
|
||||||
|
return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
var e10 = Math.sqrt(50),
|
||||||
|
e5 = Math.sqrt(10),
|
||||||
|
e2 = Math.sqrt(2);
|
||||||
|
|
||||||
|
export default function(start, stop, count) {
|
||||||
|
var reverse,
|
||||||
|
i = -1,
|
||||||
|
n,
|
||||||
|
ticks,
|
||||||
|
step;
|
||||||
|
|
||||||
|
stop = +stop, start = +start, count = +count;
|
||||||
|
if (start === stop && count > 0) return [start];
|
||||||
|
if (reverse = stop < start) n = start, start = stop, stop = n;
|
||||||
|
if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
|
||||||
|
|
||||||
|
if (step > 0) {
|
||||||
|
start = Math.ceil(start / step);
|
||||||
|
stop = Math.floor(stop / step);
|
||||||
|
ticks = new Array(n = Math.ceil(stop - start + 1));
|
||||||
|
while (++i < n) ticks[i] = (start + i) * step;
|
||||||
|
} else {
|
||||||
|
start = Math.floor(start * step);
|
||||||
|
stop = Math.ceil(stop * step);
|
||||||
|
ticks = new Array(n = Math.ceil(start - stop + 1));
|
||||||
|
while (++i < n) ticks[i] = (start - i) / step;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverse) ticks.reverse();
|
||||||
|
|
||||||
|
return ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tickIncrement(start, stop, count) {
|
||||||
|
var step = (stop - start) / Math.max(0, count),
|
||||||
|
power = Math.floor(Math.log(step) / Math.LN10),
|
||||||
|
error = step / Math.pow(10, power);
|
||||||
|
return power >= 0
|
||||||
|
? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)
|
||||||
|
: -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tickStep(start, stop, count) {
|
||||||
|
var step0 = Math.abs(stop - start) / Math.max(0, count),
|
||||||
|
step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
|
||||||
|
error = step0 / step1;
|
||||||
|
if (error >= e10) step1 *= 10;
|
||||||
|
else if (error >= e5) step1 *= 5;
|
||||||
|
else if (error >= e2) step1 *= 2;
|
||||||
|
return stop < start ? -step1 : step1;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue